home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 31 / CDASC_31_1996_juillet_aout.iso / internet / atmtim11.zip / ATOMTIME.C next >
C/C++ Source or Header  |  1996-06-05  |  7KB  |  253 lines

  1. // Atomic Time
  2. // 6-6-96 Tom Wuttke (tom@berksys.com)
  3. // Based on a VB app by Brad Greer
  4. //
  5. // Freeware
  6. //
  7. // A simple WIN32 Winsock app that sets the current system time based
  8. // on that of a remote UNIX server using port 37.  It is only accurate to
  9. // 1 second.
  10. //
  11. // Command line
  12. //   arg1 - the remote server's IP address
  13. //          (do not begin this with - or + characters if you are specifying
  14. //           a server)
  15. //   arg2 - minute offset.  adds or subtracts this many minutes to correct for any
  16. //           unknown time zone problems
  17. //
  18. //   if arg2 is omitted, I assume you want the normal time correction
  19. //   if there are no arguments, I assume the remote server is tycho.usno.navy.mil,
  20. //      a server based on military time
  21. //   if arg1 begins with a + or a -, I assume it is really arg2, and arg1 is
  22. //      the default server
  23. //
  24. // Example command lines:
  25. // AtomTime.exe tycho.usno.navy.mil -120
  26. // AtomTime.exe mail
  27. // AtomTime.exe 128.192.202.215
  28. // AtomTime +60
  29. //
  30. #define WIN32_LEAN_AND_MEAN
  31. #include <windows.h>
  32. #include <winsock.h>
  33. #include <time.h>
  34. #include <mmsystem.h>
  35. #include <stdlib.h>
  36.  
  37. char sTitle[] = "AtomicTime";
  38.  
  39.  
  40. #pragma argsused
  41. int PASCAL WinMain(HANDLE hInst, HANDLE hStupid, LPSTR sCommandLine, int mode)
  42. {
  43.     WSADATA WSAData;
  44.     int err;
  45.     struct hostent* volatile aHost;
  46.     SOCKADDR_IN sinClient, sinServer;
  47.     SOCKET s;
  48.     struct timeval timeToWait;
  49.     fd_set setRead;
  50.     DWORD remoteTime, localTime, timeDelay;
  51.     int tweakMinutes = 0;
  52.     int diff;
  53.     char sMessage[150];
  54.  
  55.     char *sServerIP = strtok(sCommandLine, " \t\\/");
  56.     char *sDelay = strtok(NULL, " \t\\/");
  57.  
  58.     // Initialize Windows sockets version 1.01
  59.     //
  60.     err = WSAStartup(0x101, &WSAData);
  61.     if (err)
  62.     {
  63.         MessageBox(0, "Could not open windows sockets.", sTitle, 0);
  64.         goto Problem1;
  65.     }
  66.  
  67.     // This address is taken from tycho.usno.navy.mil
  68.     //
  69.     sinServer.sin_addr.S_un.S_addr = 0xEF2905C0UL;
  70.  
  71.     if (sServerIP)
  72.     {
  73.         // See if it is a numerical IP number
  74.         //
  75.         if (*sServerIP == '+' || *sServerIP == '-')
  76.         {
  77.             sDelay = sServerIP;
  78.         }
  79.         else
  80.         {
  81.             sinServer.sin_addr.S_un.S_addr = ntohl(inet_addr(sServerIP));
  82.             if (sinServer.sin_addr.S_un.S_addr == INADDR_NONE)
  83.             {
  84.                 // Otherwise, look up the address using DNS
  85.                 //
  86.                 aHost = gethostbyname(sServerIP);
  87.                 if (aHost->h_addrtype != AF_INET)
  88.                 {
  89.                     MessageBox(0, "Bogus Address", sTitle, 0);
  90.                     goto Problem2;
  91.                 }
  92.                 sinServer.sin_addr.S_un.S_addr = *((LPDWORD)aHost->h_addr_list[0]);
  93.             }
  94.         }
  95.  
  96.         // If there is a second command line argument, it is the
  97.         // time offset in minutes
  98.         //
  99.         if (sDelay)
  100.         {
  101.             if (*sDelay == '+')
  102.             {
  103.                 sDelay++;
  104.             }
  105.             tweakMinutes = atoi(sDelay);
  106.         }
  107.     }
  108.  
  109.     // Set up for TCP/IP on port 37.
  110.     //
  111.     // Port 37 will return a 4-byte long integer every time a connection
  112.     // is established.  This long integer is usually the number of seconds
  113.     // past 1/1/1970, or past 1/1/1900
  114.     //
  115.     sinServer.sin_family = AF_INET;
  116.     sinServer.sin_port = htons(37);
  117.  
  118.     // Locally, we don't care about the port.
  119.     //
  120.     sinClient.sin_family = AF_INET;
  121.     sinClient.sin_addr.S_un.S_addr = INADDR_ANY;
  122.     sinClient.sin_port = 0;
  123.  
  124.     // Create a socket
  125.     //
  126.     s = socket(AF_INET, SOCK_STREAM, 0);
  127.     if (s == INVALID_SOCKET)
  128.     {
  129.         MessageBox(0, "Cannot create socket.", sTitle, 0);
  130.         goto Problem2;
  131.     }
  132.  
  133.     // Bind the socket to our local machine
  134.     //
  135.     err = bind(s, (const struct sockaddr FAR *)&sinClient, sizeof(sinClient));
  136.     if (err)
  137.     {
  138.         MessageBox(0, "Cannot bind socket to local machine.", sTitle, 0);
  139.         goto Problem3;
  140.     }
  141.  
  142.     // Begin computing the transmission delay.
  143.     // This is only useful when the delay is around 4 to 8 seconds,
  144.     // since the granularity of this clock is 1 second.
  145.     //
  146.     timeDelay = timeGetTime();
  147.  
  148.     // Connect to the remote machine on port 37
  149.     //
  150.     err = connect(s, (const struct sockaddr FAR *)&sinServer, sizeof(sinClient));
  151.     if (err)
  152.     {
  153.         MessageBox(0, "Cannot connect to remote machine.",    sTitle, 0);
  154.         goto Problem3;
  155.     }
  156.  
  157.     // Timeout after 15 seconds
  158.     //
  159.     timeToWait.tv_sec = 15;
  160.     timeToWait.tv_usec = 1;
  161.  
  162.     // We only want status on 1 socket
  163.     //
  164.     setRead.fd_count = 1;
  165.     setRead.fd_array[0] = s;
  166.  
  167.     // Wait for notification that we have received new data, or timeout
  168.     //
  169.     switch (select(0, &setRead, NULL, NULL, &timeToWait))
  170.     {
  171.         case 0:
  172.             MessageBox(0, "Remote machine timeout", sTitle, 0);
  173.             goto Problem3;
  174.  
  175.         case SOCKET_ERROR:
  176.             MessageBox(0, "Cannot read from remote machine.", sTitle, 0);
  177.             goto Problem3;
  178.     }
  179.  
  180.     // Read in the new data
  181.     //
  182.     err = recv(s, (char FAR *)&remoteTime, 4, 0);
  183.     if (err != 4)
  184.     {
  185.         MessageBox(0, "Cannot read 4 byte time code from remote machine.", sTitle, 0);
  186.           goto Problem3;
  187.     }
  188.  
  189.     // Use the connection delay/4 as an adjustment (TCP connections have 2 round
  190.     // trips to make)
  191.     //
  192.     timeDelay = (timeGetTime() - timeDelay + 500) / 4000;
  193.  
  194.     // The remote time will be in the wrong byte order, so fix it and add the
  195.     // transmission delay
  196.     //
  197.     remoteTime = ntohl(remoteTime) + timeDelay + tweakMinutes * 60;
  198.  
  199.     // Grab the current system clock's time and compute the difference
  200.     //
  201.     localTime = time(NULL);
  202.     diff = remoteTime - localTime;
  203.  
  204.     // If we are off by more than a year, chances are the remote server is using
  205.     // a different bias than 1/1/1970.
  206.     //
  207.     if (abs(diff) > 3600 * 24 * 365)
  208.     {
  209.         // Make it relative to 1900 then
  210.         // Notice the 17 leap years from 1900 to 1970, 1900 was NOT a leap year
  211.         //
  212.         remoteTime -= ((365UL * 70 + 17) * 3600 * 24);
  213.         diff = remoteTime - localTime;
  214.     }
  215.  
  216.     // If we are off by more than 30 minutes, warn the user - since there may be
  217.     // a time zone or daylight saving problem.
  218.     //
  219.     if (abs(diff) > 1800)
  220.     {
  221.         char sRemoteTime[30], sLocalTime[30];
  222.  
  223.         wsprintf(sRemoteTime, ctime((const time_t *)&remoteTime));
  224.         wsprintf(sLocalTime, ctime((const time_t *)&localTime));
  225.  
  226.         wsprintf(sMessage, "Remote Time is %s\nLocal Time is %s\n"
  227.             "The time zone might be incorrect.\nAre you sure"
  228.             " you want to set the system clock\nto the remote time?",
  229.             sRemoteTime, sLocalTime);
  230.         if (MessageBox(0, sMessage, sTitle, MB_YESNO) == IDNO)
  231.         {
  232.             goto Problem3;
  233.         }
  234.     }
  235.  
  236.     // Recompute the current system time plus the required adjustment, and set
  237.     // the user's system time.
  238.     //
  239.     localTime = time(NULL) + diff;
  240.     stime((time_t *)&localTime);
  241.  
  242.     // Shutdown
  243. Problem3:
  244.     closesocket(s);
  245.  
  246. Problem2:
  247.     WSACleanup();
  248.  
  249. Problem1:
  250.     return 0;
  251. }
  252.  
  253.