mirror of
https://github.com/HamletDuFromage/aio-switch-updater.git
synced 2024-11-09 12:01:44 +00:00
255 lines
8.5 KiB
C++
255 lines
8.5 KiB
C++
|
/* This is free and unencumbered software released into the public domain.
|
||
|
|
||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||
|
distribute this software, either in source code form or as a compiled
|
||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||
|
means.
|
||
|
|
||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||
|
of this software dedicate any and all copyright interest in the
|
||
|
software to the public domain. We make this dedication for the benefit
|
||
|
of the public at large and to the detriment of our heirs and
|
||
|
successors. We intend this dedication to be an overt act of
|
||
|
relinquishment in perpetuity of all present and future rights to this
|
||
|
software under copyright law.
|
||
|
|
||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
For more information, please refer to <http://unlicense.org>
|
||
|
|
||
|
Additionally, the ntp_packet struct uses code licensed under the BSD 3-clause. See LICENSE-THIRD-PARTY for more information. */
|
||
|
|
||
|
#include "ntcp.hpp"
|
||
|
|
||
|
#include <cstring>
|
||
|
#include <sstream>
|
||
|
#include <time.h>
|
||
|
#include <arpa/inet.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/socket.h>
|
||
|
#include <netinet/in.h>
|
||
|
#include <netdb.h>
|
||
|
#include <errno.h>
|
||
|
#include <stdarg.h>
|
||
|
#include <string>
|
||
|
|
||
|
#include <switch.h>
|
||
|
|
||
|
#define NTP_TIMESTAMP_DELTA 2208988800ull
|
||
|
|
||
|
/* ------------- BEGIN BSD 3-CLAUSE LICENSED CODE-------------------- */
|
||
|
// https://www.cisco.com/c/en/us/about/press/internet-protocol-journal/back-issues/table-contents-58/154-ntp.html
|
||
|
// Struct adapted from https://github.com/lettier/ntpclient , see LICENSE-THIRD-PARTY for more information.
|
||
|
typedef struct
|
||
|
{
|
||
|
uint8_t li_vn_mode; // li: two bits, leap indicator. vn: three bits, protocol version number. mode: three bits, client mode.
|
||
|
|
||
|
uint8_t stratum; // Stratum level of the local clock.
|
||
|
uint8_t poll; // Maximum interval between successive messages.
|
||
|
uint8_t precision; // Precision of the local clock.
|
||
|
|
||
|
uint32_t rootDelay; // Total round trip delay time.
|
||
|
uint32_t rootDispersion; // Max error allowed from primary clock source.
|
||
|
uint32_t refId; // Reference clock identifier.
|
||
|
|
||
|
uint32_t refTm_s; // Reference time-stamp seconds.
|
||
|
uint32_t refTm_f; // Reference time-stamp fraction of a second.
|
||
|
|
||
|
uint32_t origTm_s; // Originate time-stamp seconds.
|
||
|
uint32_t origTm_f; // Originate time-stamp fraction of a second.
|
||
|
|
||
|
uint32_t rxTm_s; // Received time-stamp seconds.
|
||
|
uint32_t rxTm_f; // Received time-stamp fraction of a second.
|
||
|
|
||
|
uint32_t txTm_s; // Transmit time-stamp seconds.
|
||
|
uint32_t txTm_f; // Transmit time-stamp fraction of a second.
|
||
|
} ntp_packet;
|
||
|
/* ------------- END BSD 3-CLAUSE LICENSED CODE-------------------- */
|
||
|
|
||
|
void serviceCleanup(void)
|
||
|
{
|
||
|
nifmExit();
|
||
|
setsysExit();
|
||
|
timeExit();
|
||
|
}
|
||
|
|
||
|
void print(const char *msg)
|
||
|
{
|
||
|
puts(msg);
|
||
|
consoleUpdate(NULL);
|
||
|
}
|
||
|
|
||
|
void printWithArgs(const char *msg, ...)
|
||
|
{
|
||
|
va_list args;
|
||
|
va_start(args, msg);
|
||
|
vprintf(msg, args);
|
||
|
va_end(args);
|
||
|
consoleUpdate(NULL);
|
||
|
}
|
||
|
|
||
|
// We need system service access, not just user (the default)
|
||
|
|
||
|
std::string syncTime()
|
||
|
{
|
||
|
const char *server_name = "0.pool.ntp.org";
|
||
|
const uint16_t port = 123;
|
||
|
int sockfd = -1;
|
||
|
std::stringstream out;
|
||
|
|
||
|
int res = 0;
|
||
|
time_t tim;
|
||
|
|
||
|
Result rs = timeInitialize();
|
||
|
if(R_FAILED(rs))
|
||
|
{
|
||
|
//printWithArgs("Failed to init time services, error code %x\n", rs);
|
||
|
out << "Failed to init time services, error code " << rs << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
rs = nifmInitialize(NifmServiceType_User);
|
||
|
if(R_FAILED(rs))
|
||
|
{
|
||
|
//printWithArgs("Failed to init nifm services, with error code %x\n", rs);
|
||
|
out << "Failed to init nifm services, with error code " << rs << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
NifmInternetConnectionStatus nifmICS;
|
||
|
rs = nifmGetInternetConnectionStatus(NULL, NULL, &nifmICS);
|
||
|
if(R_FAILED(rs))
|
||
|
{
|
||
|
//printWithArgs("Failed to get internet connection status, with error code %x\nPlease ensure your console is connected to the internet, and try again.\n", rs);
|
||
|
out << "Failed to get internet connection status, with error code " << res << ". Please ensure your console is connected to the internet, and try again." << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
if(nifmICS != NifmInternetConnectionStatus_Connected)
|
||
|
{
|
||
|
//print("You're not connected to the internet. Please run this application again after connecting.");
|
||
|
out << "You're not connected to the internet. Please run this application again after connecting." << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
ntp_packet packet;
|
||
|
memset(&packet, 0, sizeof(ntp_packet));
|
||
|
|
||
|
packet.li_vn_mode = (0 << 6) | (4 << 3) | 3; // LI 0 | Client version 4 | Mode 3
|
||
|
|
||
|
packet.txTm_s = htonl(NTP_TIMESTAMP_DELTA + time(NULL)); // Current networktime on the console
|
||
|
|
||
|
struct sockaddr_in serv_addr;
|
||
|
struct hostent *server;
|
||
|
|
||
|
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||
|
if(sockfd < 0)
|
||
|
{
|
||
|
//printWithArgs("Failed to open socket with error code %x\n", errno);
|
||
|
out << "Failed to open socket with error code " << errno << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
//print("Opened socket");
|
||
|
//printWithArgs("Attempting to connect to %s\n", server_name);
|
||
|
errno = 0;
|
||
|
if((server = gethostbyname(server_name)) == NULL)
|
||
|
{
|
||
|
//printWithArgs("Gethostbyname failed: %x\n", errno);
|
||
|
out << "Gethostbyname failed: " << errno << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
memset(&serv_addr, 0, sizeof(struct sockaddr_in));
|
||
|
|
||
|
serv_addr.sin_family = AF_INET;
|
||
|
|
||
|
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr_list[0], 4);
|
||
|
|
||
|
serv_addr.sin_port = htons(port);
|
||
|
|
||
|
errno = 0;
|
||
|
if((res = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) < 0)
|
||
|
{
|
||
|
//printWithArgs("Connect failed: %x %x\n", res, errno);
|
||
|
out << "Connect failed: " << res << " " << errno << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
errno = 0;
|
||
|
if((res = send(sockfd, (char *)&packet, sizeof(ntp_packet), 0)) < 0)
|
||
|
{
|
||
|
//printWithArgs("Error writing to socket: %x %x\n", res, errno);
|
||
|
out << "Error writing to socket: " << res << " " << errno << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
printWithArgs("Sent time request with result: %x %x, waiting for response...\n", res, errno);
|
||
|
|
||
|
errno = 0;
|
||
|
if((res = recv(sockfd, (char *)&packet, sizeof(ntp_packet), 0)) < sizeof(ntp_packet))
|
||
|
{
|
||
|
//printWithArgs("Error reading from socket: %x %x\n", res, errno);
|
||
|
out << "Error reading from socket: " << res << " " << errno << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
packet.txTm_s = ntohl(packet.txTm_s);
|
||
|
|
||
|
tim = (time_t) (packet.txTm_s - NTP_TIMESTAMP_DELTA);
|
||
|
|
||
|
rs = timeSetCurrentTime(TimeType_NetworkSystemClock, (uint64_t)tim);
|
||
|
if(R_FAILED(rs))
|
||
|
{
|
||
|
//printWithArgs("Failed to set NetworkSystemClock, %x\n", rs);
|
||
|
out << "Failed to set NetworkSystemClock " << rs << std::endl;
|
||
|
}
|
||
|
else
|
||
|
out << "Successfully set NetworkSystemClock" << std::endl;
|
||
|
|
||
|
rs = setsysInitialize();
|
||
|
if(R_FAILED(rs))
|
||
|
{
|
||
|
//printWithArgs("setsysInitialize failed, %x\n", rs);
|
||
|
out << "setsysInitialize failed, " << rs << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
bool internetTimeSync;
|
||
|
|
||
|
rs = setsysIsUserSystemClockAutomaticCorrectionEnabled(&internetTimeSync);
|
||
|
if(R_FAILED(rs) || internetTimeSync == false)
|
||
|
{
|
||
|
//printWithArgs("Unable to detect if internet time sync is enabled, %x\n", rs);
|
||
|
out << "Note: internet time sync is not enabled (enabling it will correct the time on the home screen)" << std::endl;
|
||
|
goto done;
|
||
|
}
|
||
|
|
||
|
/* if(internetTimeSync == false)
|
||
|
{
|
||
|
print("Internet time sync is not enabled (enabling it will correct the time on the home screen, and this prompt will not appear again).\nPress A to enable internet time sync (and restart the console), or PLUS to quit.");
|
||
|
rs = setsysSetUserSystemClockAutomaticCorrectionEnabled(true);
|
||
|
if(R_SUCCEEDED(rs))
|
||
|
{
|
||
|
serviceCleanup();
|
||
|
bpcInitialize();
|
||
|
bpcRebootSystem();
|
||
|
bpcExit();
|
||
|
}
|
||
|
} */
|
||
|
|
||
|
done:
|
||
|
|
||
|
cleanup:
|
||
|
if(sockfd != -1)
|
||
|
close(sockfd);
|
||
|
serviceCleanup();
|
||
|
return out.str();
|
||
|
}
|