home *** CD-ROM | disk | FTP | other *** search
- // Atomic Time
- // 6-6-96 Tom Wuttke (tom@berksys.com)
- // Based on a VB app by Brad Greer
- //
- // Freeware
- //
- // A simple WIN32 Winsock app that sets the current system time based
- // on that of a remote UNIX server using port 37. It is only accurate to
- // 1 second.
- //
- // Command line
- // arg1 - the remote server's IP address
- // (do not begin this with - or + characters if you are specifying
- // a server)
- // arg2 - minute offset. adds or subtracts this many minutes to correct for any
- // unknown time zone problems
- //
- // if arg2 is omitted, I assume you want the normal time correction
- // if there are no arguments, I assume the remote server is tycho.usno.navy.mil,
- // a server based on military time
- // if arg1 begins with a + or a -, I assume it is really arg2, and arg1 is
- // the default server
- //
- // Example command lines:
- // AtomTime.exe tycho.usno.navy.mil -120
- // AtomTime.exe mail
- // AtomTime.exe 128.192.202.215
- // AtomTime +60
- //
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <winsock.h>
- #include <time.h>
- #include <mmsystem.h>
- #include <stdlib.h>
-
- char sTitle[] = "AtomicTime";
-
-
- #pragma argsused
- int PASCAL WinMain(HANDLE hInst, HANDLE hStupid, LPSTR sCommandLine, int mode)
- {
- WSADATA WSAData;
- int err;
- struct hostent* volatile aHost;
- SOCKADDR_IN sinClient, sinServer;
- SOCKET s;
- struct timeval timeToWait;
- fd_set setRead;
- DWORD remoteTime, localTime, timeDelay;
- int tweakMinutes = 0;
- int diff;
- char sMessage[150];
-
- char *sServerIP = strtok(sCommandLine, " \t\\/");
- char *sDelay = strtok(NULL, " \t\\/");
-
- // Initialize Windows sockets version 1.01
- //
- err = WSAStartup(0x101, &WSAData);
- if (err)
- {
- MessageBox(0, "Could not open windows sockets.", sTitle, 0);
- goto Problem1;
- }
-
- // This address is taken from tycho.usno.navy.mil
- //
- sinServer.sin_addr.S_un.S_addr = 0xEF2905C0UL;
-
- if (sServerIP)
- {
- // See if it is a numerical IP number
- //
- if (*sServerIP == '+' || *sServerIP == '-')
- {
- sDelay = sServerIP;
- }
- else
- {
- sinServer.sin_addr.S_un.S_addr = ntohl(inet_addr(sServerIP));
- if (sinServer.sin_addr.S_un.S_addr == INADDR_NONE)
- {
- // Otherwise, look up the address using DNS
- //
- aHost = gethostbyname(sServerIP);
- if (aHost->h_addrtype != AF_INET)
- {
- MessageBox(0, "Bogus Address", sTitle, 0);
- goto Problem2;
- }
- sinServer.sin_addr.S_un.S_addr = *((LPDWORD)aHost->h_addr_list[0]);
- }
- }
-
- // If there is a second command line argument, it is the
- // time offset in minutes
- //
- if (sDelay)
- {
- if (*sDelay == '+')
- {
- sDelay++;
- }
- tweakMinutes = atoi(sDelay);
- }
- }
-
- // Set up for TCP/IP on port 37.
- //
- // Port 37 will return a 4-byte long integer every time a connection
- // is established. This long integer is usually the number of seconds
- // past 1/1/1970, or past 1/1/1900
- //
- sinServer.sin_family = AF_INET;
- sinServer.sin_port = htons(37);
-
- // Locally, we don't care about the port.
- //
- sinClient.sin_family = AF_INET;
- sinClient.sin_addr.S_un.S_addr = INADDR_ANY;
- sinClient.sin_port = 0;
-
- // Create a socket
- //
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s == INVALID_SOCKET)
- {
- MessageBox(0, "Cannot create socket.", sTitle, 0);
- goto Problem2;
- }
-
- // Bind the socket to our local machine
- //
- err = bind(s, (const struct sockaddr FAR *)&sinClient, sizeof(sinClient));
- if (err)
- {
- MessageBox(0, "Cannot bind socket to local machine.", sTitle, 0);
- goto Problem3;
- }
-
- // Begin computing the transmission delay.
- // This is only useful when the delay is around 4 to 8 seconds,
- // since the granularity of this clock is 1 second.
- //
- timeDelay = timeGetTime();
-
- // Connect to the remote machine on port 37
- //
- err = connect(s, (const struct sockaddr FAR *)&sinServer, sizeof(sinClient));
- if (err)
- {
- MessageBox(0, "Cannot connect to remote machine.", sTitle, 0);
- goto Problem3;
- }
-
- // Timeout after 15 seconds
- //
- timeToWait.tv_sec = 15;
- timeToWait.tv_usec = 1;
-
- // We only want status on 1 socket
- //
- setRead.fd_count = 1;
- setRead.fd_array[0] = s;
-
- // Wait for notification that we have received new data, or timeout
- //
- switch (select(0, &setRead, NULL, NULL, &timeToWait))
- {
- case 0:
- MessageBox(0, "Remote machine timeout", sTitle, 0);
- goto Problem3;
-
- case SOCKET_ERROR:
- MessageBox(0, "Cannot read from remote machine.", sTitle, 0);
- goto Problem3;
- }
-
- // Read in the new data
- //
- err = recv(s, (char FAR *)&remoteTime, 4, 0);
- if (err != 4)
- {
- MessageBox(0, "Cannot read 4 byte time code from remote machine.", sTitle, 0);
- goto Problem3;
- }
-
- // Use the connection delay/4 as an adjustment (TCP connections have 2 round
- // trips to make)
- //
- timeDelay = (timeGetTime() - timeDelay + 500) / 4000;
-
- // The remote time will be in the wrong byte order, so fix it and add the
- // transmission delay
- //
- remoteTime = ntohl(remoteTime) + timeDelay + tweakMinutes * 60;
-
- // Grab the current system clock's time and compute the difference
- //
- localTime = time(NULL);
- diff = remoteTime - localTime;
-
- // If we are off by more than a year, chances are the remote server is using
- // a different bias than 1/1/1970.
- //
- if (abs(diff) > 3600 * 24 * 365)
- {
- // Make it relative to 1900 then
- // Notice the 17 leap years from 1900 to 1970, 1900 was NOT a leap year
- //
- remoteTime -= ((365UL * 70 + 17) * 3600 * 24);
- diff = remoteTime - localTime;
- }
-
- // If we are off by more than 30 minutes, warn the user - since there may be
- // a time zone or daylight saving problem.
- //
- if (abs(diff) > 1800)
- {
- char sRemoteTime[30], sLocalTime[30];
-
- wsprintf(sRemoteTime, ctime((const time_t *)&remoteTime));
- wsprintf(sLocalTime, ctime((const time_t *)&localTime));
-
- wsprintf(sMessage, "Remote Time is %s\nLocal Time is %s\n"
- "The time zone might be incorrect.\nAre you sure"
- " you want to set the system clock\nto the remote time?",
- sRemoteTime, sLocalTime);
- if (MessageBox(0, sMessage, sTitle, MB_YESNO) == IDNO)
- {
- goto Problem3;
- }
- }
-
- // Recompute the current system time plus the required adjustment, and set
- // the user's system time.
- //
- localTime = time(NULL) + diff;
- stime((time_t *)&localTime);
-
- // Shutdown
- Problem3:
- closesocket(s);
-
- Problem2:
- WSACleanup();
-
- Problem1:
- return 0;
- }
-
-