2020-12-27 17:11:40 +00:00
/* 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>
2020-12-28 18:28:58 +00:00
Additionally , the ntp_packet struct uses code licensed under the BSD 3 - clause . */
/* This homebrew uses code from https://github.com/lettier/ntpclient under the following license:
BSD 3 - Clause License
Copyright ( c ) 2014 , David Lettier
All rights reserved .
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions are met :
* Redistributions of source code must retain the above copyright notice , this
list of conditions and the following disclaimer .
* Redistributions in binary form must reproduce the above copyright notice ,
this list of conditions and the following disclaimer in the documentation
and / or other materials provided with the distribution .
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-12-27 17:11:40 +00:00
2020-12-27 17:19:16 +00:00
// This code comes from https://github.com/thedax/NX-ntpc, thank you for your work
2020-12-27 17:11:40 +00:00
# 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). \n Press 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 ( ) ;
}