mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@616 385bec56-5757-e545-9c3a-d8741f4650f1
310 lines
11 KiB
C++
310 lines
11 KiB
C++
/*---------------------------------------------------------------------------*
|
|
Project: Horizon
|
|
File: NtpClient.cpp
|
|
|
|
Copyright 2009 Nintendo. All rights reserved.
|
|
|
|
These coded instructions, statements, and computer programs contain
|
|
proprietary information of Nintendo of America Inc. and/or Nintendo
|
|
Company Ltd., and are protected by Federal copyright law. They may
|
|
not be disclosed to third parties or copied or duplicated in any form,
|
|
in whole or in part, without the prior written consent of Nintendo.
|
|
|
|
$Rev$
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
#include <nn.h>
|
|
#include <nn/socket.h>
|
|
#include <nn/ac.h>
|
|
#include <nn/ptm.h>
|
|
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
|
|
#include <nn/ac/private/ac.h>
|
|
#include <nn/ac/CTR/private/ac_InternalApi.h>
|
|
#include <nn/ac/CTR/private/ac_NetworkSetting.h>
|
|
#include <nn/math.h>
|
|
|
|
#include "Importer.h"
|
|
#include "CommonLogger.h"
|
|
|
|
namespace ConsoleRestore
|
|
{
|
|
|
|
namespace {
|
|
|
|
const size_t NTP_THREAD_STACK_SIZE = 0x1000;
|
|
nn::os::Thread s_NtpThread;
|
|
nn::os::StackBuffer<NTP_THREAD_STACK_SIZE> s_NtpThreadStack;
|
|
bool s_NtpSyncSuccessed = false;
|
|
|
|
|
|
struct NTP_Packet{ // NTPパケット
|
|
u32 controlWord;
|
|
u32 rootDelay;
|
|
u32 rootDispersion;
|
|
u32 referenceId;
|
|
s64 referenceTimestamp;
|
|
s64 startTimestamp;
|
|
s64 receiveTimestamp;
|
|
u32 transmitTimestampSeconds;
|
|
u32 transmitTimestampFractions;
|
|
};
|
|
|
|
const size_t TIMEOUT_MILLISECOND = 5000; // タイムアウト ミリ秒数
|
|
NTP_Packet s_NTPSendPacket; // 送信するNTPパケット
|
|
NTP_Packet s_NTPRecvPacket; // 受信するNTPパケット
|
|
const u32 NTP_PORT_NUM = 123;
|
|
|
|
bool GetNtpTime(u32* ntpTime)
|
|
{
|
|
nn::Result result;
|
|
|
|
bool retval = true;
|
|
NN_LOG("Initializing network.\n");
|
|
|
|
// 本体に書き込まれているネットワーク設定を使ってネットワーク接続を初期化
|
|
if(!nn::ac::IsConnected())
|
|
{
|
|
result = common::InitializeNetwork();
|
|
COMMON_LOGGER_RESULT_IF_FAILED(result);
|
|
}
|
|
|
|
{
|
|
NN_LOG("Initializing socket..\n");
|
|
|
|
// 一つのスレッドからソケット API を利用する
|
|
const s32 sessionCount = 1;
|
|
// ソケットの送受信バッファとして 64 KB を割り当て
|
|
const size_t bufferSizeForSockets = 65536;
|
|
// ソケットライブラリに必要なワークサイズを求める
|
|
const size_t workSizeForLibrary = nn::socket::GetRequiredMemorySize(bufferSizeForSockets, sessionCount);
|
|
|
|
// ワークメモリを確保して 4KB にアラインにする
|
|
u8* pWorkMemory = new u8[workSizeForLibrary + 4096];
|
|
uptr workMemoryAddress = nn::math::RoundUp<uptr>(reinterpret_cast<uptr> (pWorkMemory), 4096);
|
|
|
|
// ソケットライブラリの初期化
|
|
result = nn::socket::Initialize(workMemoryAddress, workSizeForLibrary, bufferSizeForSockets, sessionCount);
|
|
COMMON_LOGGER_RESULT_IF_FAILED(result);
|
|
|
|
{
|
|
s32 ret;
|
|
nn::socket::InAddr addr, netmask;
|
|
ret = nn::socket::GetPrimaryAddress(reinterpret_cast<u8*> (&addr), reinterpret_cast<u8*> (&netmask));
|
|
NN_ASSERT(ret == 0);
|
|
COMMON_LOGGER("host : %s\n", nn::socket::InetNtoA(addr));
|
|
COMMON_LOGGER("netmask : %s\n", nn::socket::InetNtoA(netmask));
|
|
|
|
nn::socket::InAddr dns1, dns2;
|
|
ret = nn::socket::GetResolver(reinterpret_cast<u8*> (&dns1), reinterpret_cast<u8*> (&dns2));
|
|
if (ret == 0)
|
|
{
|
|
COMMON_LOGGER("dns1 : %s\n", nn::socket::InetNtoA(dns1));
|
|
COMMON_LOGGER("dns2 : %s\n", nn::socket::InetNtoA(dns2));
|
|
}
|
|
|
|
nn::socket::InAddr gateway;
|
|
ret = nn::socket::GetDefaultGateway(reinterpret_cast<u8*> (&gateway));
|
|
if (ret == 0)
|
|
{
|
|
COMMON_LOGGER("gateway : %s\n", nn::socket::InetNtoA(gateway));
|
|
}
|
|
|
|
COMMON_LOGGER("\n");
|
|
#ifndef NN_SWITCH_DISABLE_DEBUG_PRINT
|
|
nn::socket::DumpRoutingTable();
|
|
#endif
|
|
}
|
|
|
|
{
|
|
s32 socket = nn::socket::Socket(nn::socket::PF_INET, nn::socket::SOCK_DGRAM, 0);
|
|
NN_LOG("socket = %d\n", socket);
|
|
|
|
// クライアントアドレスの設定
|
|
nn::socket::SockAddrIn host_addr;
|
|
host_addr.len = sizeof(nn::socket::SockAddrIn);
|
|
host_addr.family = nn::socket::AF_INET;
|
|
host_addr.addr.addr = 0;
|
|
host_addr.port = nn::socket::HtoNs(NTP_PORT_NUM);
|
|
|
|
// ローカルアドレスをバインド
|
|
s32 ret = nn::socket::Bind(socket, &host_addr);
|
|
NN_LOG("bind = %d\n", ret);
|
|
|
|
// ********************************************************************************
|
|
// NTPパケットを生成して送る
|
|
// ********************************************************************************
|
|
|
|
// サーバアドレスの設定
|
|
nn::socket::SockAddrIn serverSockAddrIn;
|
|
serverSockAddrIn.len = sizeof(nn::socket::SockAddrIn);
|
|
serverSockAddrIn.family = nn::socket::AF_INET;
|
|
|
|
// GetHostByNameを使う場合
|
|
nn::socket::HostEnt* serverHostent;
|
|
u64 serveraddr = 0;
|
|
serverHostent = nn::socket::GetHostByName(GetNtpServerName());
|
|
if (serverHostent == NULL)
|
|
{
|
|
COMMON_LOGGER("Error: GetHostByName %s\n", GetNtpServerName());
|
|
retval = false;
|
|
}
|
|
else
|
|
{
|
|
// サーバのホスト情報からIPアドレスをコピー
|
|
serveraddr = *(reinterpret_cast<u64 *> (serverHostent->addrList[0]));
|
|
}
|
|
serverSockAddrIn.addr.addr = serveraddr;
|
|
COMMON_LOGGER("Destination address: %s\n", nn::socket::InetNtoA(serverSockAddrIn.addr));
|
|
serverSockAddrIn.port = nn::socket::HtoNs(NTP_PORT_NUM); // ポート番号
|
|
|
|
// NTPパケットをSNTP用に初期化する
|
|
s_NTPSendPacket.controlWord = nn::socket::HtoNl(0x0B000000);
|
|
s_NTPSendPacket.rootDelay = 0;
|
|
s_NTPSendPacket.rootDispersion = 0;
|
|
s_NTPSendPacket.referenceId = 0;
|
|
s_NTPSendPacket.referenceTimestamp = 0;
|
|
s_NTPSendPacket.startTimestamp = 0;
|
|
s_NTPSendPacket.receiveTimestamp = 0;
|
|
s_NTPSendPacket.transmitTimestampSeconds = 0;
|
|
s_NTPSendPacket.transmitTimestampFractions = 0;
|
|
|
|
// サーバを指定してNTPパケットを送信する
|
|
if ((ret = nn::socket::SendTo(socket, reinterpret_cast<const void*> (&s_NTPSendPacket), sizeof(s_NTPSendPacket), 0,
|
|
&serverSockAddrIn)) < 0)
|
|
{
|
|
COMMON_LOGGER("Error: Failed Send to Server, %d\n", ret);
|
|
retval = false;
|
|
}
|
|
|
|
NN_LOG("SendTo finished\n");
|
|
|
|
// 受信待ち
|
|
nn::socket::PollFd pollFd;
|
|
pollFd.fd = socket;
|
|
pollFd.events = nn::socket::POLLRDNORM;
|
|
if ((ret = nn::socket::Poll(&pollFd, 1, TIMEOUT_MILLISECOND)) < 0)
|
|
{
|
|
COMMON_LOGGER("Error: recv error, %d\n", ret);
|
|
retval = false;
|
|
}
|
|
|
|
NN_LOG("Poll Finished\n");
|
|
|
|
switch (pollFd.revents)
|
|
{
|
|
case nn::socket::POLLERR: // ソケットにエラーが発生しました。
|
|
COMMON_LOGGER("Error: POLLERR %s %d\n", __func__, __LINE__);
|
|
retval = false;
|
|
break;
|
|
case nn::socket::POLLHUP: // ストリーム・ソケットが未接続です。
|
|
COMMON_LOGGER("Error: POLLHUP %s %d\n", __func__, __LINE__);
|
|
retval = false;
|
|
break;
|
|
case nn::socket::POLLNVAL: // 不正なソケット記述子です。
|
|
COMMON_LOGGER("Error: POLLNVAL %s %d\n", __func__, __LINE__);
|
|
retval = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// サーバから時刻情報を受信する
|
|
// サーバを指定して受信を行う
|
|
// 受信するまで待たされる
|
|
if ((ret = nn::socket::RecvFrom(socket, reinterpret_cast<void*> (&s_NTPRecvPacket), sizeof(s_NTPRecvPacket), nn::socket::MSG_DONTWAIT,
|
|
&serverSockAddrIn)) < 0)
|
|
{
|
|
COMMON_LOGGER("Error: RecvFrom, %d\n", ret);
|
|
retval = false;
|
|
}
|
|
|
|
NN_LOG("RecvFrom finished\n");
|
|
|
|
// NTPサーバから取得した時刻を現地時間に変換する
|
|
*ntpTime = nn::socket::NtoHl(s_NTPRecvPacket.transmitTimestampSeconds) - 2208988800; /* 1970/01/01 からの秒数に変換 */
|
|
NN_LOG("ntp_time = %d\n", ntpTime);
|
|
|
|
nn::socket::Close(socket);
|
|
NN_UNUSED_VAR(ret);
|
|
}
|
|
|
|
NN_LOG("Finalizing socket..\n");
|
|
// ソケットライブラリの終了
|
|
result = nn::socket::Finalize();
|
|
COMMON_LOGGER_RESULT_IF_FAILED(result);
|
|
}
|
|
|
|
NN_LOG("Finalizing network.\n");
|
|
result = common::FinalizeNetwork();
|
|
COMMON_LOGGER_RESULT_IF_FAILED(result);
|
|
|
|
return retval;
|
|
}
|
|
|
|
}
|
|
|
|
void NtpThreadFunc()
|
|
{
|
|
// NTP時間を取得する
|
|
u32 ntpTime;
|
|
if (GetNtpTime(&ntpTime))
|
|
{
|
|
// タイムゾーンを考慮してDateTimeに変換する
|
|
TimeZone timeZone = GetTimeZone();
|
|
|
|
// 1970/01/01
|
|
nn::fnd::DateTime utc = nn::fnd::DateTime(1970, 1, 1, 0, 0, 0, 0);
|
|
nn::fnd::DateTime current = utc + nn::fnd::TimeSpan::FromSeconds(ntpTime);
|
|
|
|
if (timeZone.isMinus)
|
|
{
|
|
current -= (nn::fnd::TimeSpan::FromHours(timeZone.hour) + nn::fnd::TimeSpan::FromMinutes(timeZone.minutes));
|
|
}
|
|
else
|
|
{
|
|
current += nn::fnd::TimeSpan::FromHours(timeZone.hour) + nn::fnd::TimeSpan::FromMinutes(timeZone.minutes);
|
|
}
|
|
|
|
// SWCを書き込む
|
|
nn::ptm::CTR::SetUserTime(current);
|
|
|
|
COMMON_LOGGER("Set User Time %04d/%02d/%02d %02d:%02d:%02d\n",
|
|
current.GetYear(), current.GetMonth(), current.GetDay(), current.GetHour(), current.GetMinute(), current.GetSecond());
|
|
|
|
s_NtpSyncSuccessed = true;
|
|
}
|
|
else
|
|
{
|
|
COMMON_LOGGER("Failed Get Ntp Time\n");
|
|
s_NtpSyncSuccessed = false;
|
|
}
|
|
}
|
|
|
|
bool IsTimeAdjustFinished()
|
|
{
|
|
// Initialize済みかつ終了
|
|
return s_NtpThread.IsValid() && !s_NtpThread.IsAlive();
|
|
}
|
|
|
|
bool IsTimeAdjustSuccessed()
|
|
{
|
|
return s_NtpSyncSuccessed;
|
|
}
|
|
|
|
void AdjustTime()
|
|
{
|
|
nn::Result result;
|
|
|
|
result = nn::ac::CTR::InitializeInternal();
|
|
COMMON_LOGGER_RESULT_IF_FAILED(result);
|
|
|
|
if(IsTimeAdjustFinished())
|
|
{
|
|
s_NtpThread.Join();
|
|
s_NtpThread.Finalize();
|
|
}
|
|
s_NtpThread.Start( NtpThreadFunc, s_NtpThreadStack);
|
|
}
|
|
|
|
}
|