home *** CD-ROM | disk | FTP | other *** search
/ DOS/V Power Report 2001 June / VPR0106A.BIN / OLS / TCL228 / TCL228.lzh / EXESRC.lzh / sntp.c < prev    next >
C/C++ Source or Header  |  1999-09-18  |  18KB  |  698 lines

  1. /*-------------------------------------------------------------
  2.   sntp.c
  3.   KAZUBON 1998-1999
  4.                Special thanks to Tomoaki Nakashima
  5. ---------------------------------------------------------------*/
  6.  
  7. #include "tclock.h"
  8.  
  9. #include <winsock.h>
  10. #include <ras.h>
  11. #include "resource.h"
  12.  
  13. #undef RasEnumConnections
  14. #undef RasGetConnectStatus
  15.  
  16. // functions
  17. LRESULT CALLBACK SNTPWndProc(HWND hwnd, UINT message,
  18.     WPARAM wParam, LPARAM lParam);
  19. static BOOL IsConnecting(void);
  20. static void SNTPStart(HWND hwnd, char *buf);
  21. static void OnGetHost(HWND hwnd, WPARAM wParam, LPARAM lParam);
  22. static void SNTPSend(HWND hwnd, unsigned long serveraddr);
  23. static void OnReceive(HWND hwnd, WPARAM wParam, LPARAM lParam);
  24. static void SynchronizeSystemTime(DWORD seconds, DWORD fractions);
  25. static void SocketClose(HWND hwnd, const char *msgbuf);
  26. static int GetServerPort(const char *buf, char *server);
  27. static void Log(const char* msg);
  28. void time2int(int* ph, int* pm, const char* src);
  29.  
  30. // globals for TClock
  31. static BOOL bFirst = TRUE;
  32. static BOOL bSendingData = FALSE;
  33. static BOOL bSyncTimer = FALSE;
  34. static BOOL bSyncADay = TRUE;
  35. static int nMinutes = 60;
  36. static BOOL bNoDial = TRUE;
  37. static int nTimeout = 1000;
  38. static int nLastDay = -1;
  39. static int nLastMinute = -1;
  40. static int nHourStart = -1, nMinuteStart = -1,
  41.     nHourEnd = -1, nMinuteEnd = -1;
  42. static int nMinuteDif = 0;
  43. static DWORD dwTickCount = 0;
  44. static DWORD dwTickCountOnGetHost = 0;
  45. static DWORD dwTickCountOnSend = 0;
  46. DWORD (WINAPI *RasEnumConnections)(LPRASCONN, LPDWORD, LPDWORD);
  47. DWORD (WINAPI *RasGetConnectStatus)(HRASCONN, LPRASCONNSTATUS);
  48. static HMODULE hRASAPI = NULL;
  49.  
  50. static char* g_pGetHost = NULL; // buffer of host entry
  51. static HANDLE g_hGetHost;       // task handle of WSAAsyncGetHostByName()
  52. static int g_socket;   // socket
  53. static int g_port;     // port numer
  54.  
  55. struct NTP_Packet {          // NTP packet
  56.     int Control_Word;
  57.     int root_delay;
  58.     int root_dispersion;
  59.     int reference_identifier;
  60.     __int64 reference_timestamp;
  61.     __int64 originate_timestamp;
  62.     __int64 receive_timestamp;
  63.     int transmit_timestamp_seconds;
  64.     int transmit_timestamp_fractions;
  65. };
  66.  
  67. // notification of event to get host
  68. #define WSOCK_GETHOST (WM_USER+1)
  69. // notification of socket event
  70. #define WSOCK_SELECT  (WM_USER+2)
  71.  
  72. /*---------------------------------------------------
  73.     create a window, initialize WinSock
  74. ---------------------------------------------------*/
  75. BOOL InitSyncTime(HWND hwndParent)
  76. {
  77.     char classname[] = "TClockSNTPWnd";
  78.     WNDCLASS wndclass;
  79.     WORD wVersionRequested;
  80.     int  nErrorStatus;
  81.     WSADATA wsaData;
  82.     
  83.     g_socket = -1;
  84.     g_hGetHost = NULL;
  85.     
  86.     // initialize WinSock
  87.     wVersionRequested = MAKEWORD(1, 1);
  88.     nErrorStatus = WSAStartup(wVersionRequested, &wsaData);
  89.     if(nErrorStatus != 0)
  90.     {
  91.         Log("failed to initialize");
  92.         return FALSE;
  93.     }
  94.     
  95.     // load DLL of RAS API
  96.     
  97.     if(!GetMyRegLong("SNTP", "NoRASAPI", FALSE))
  98.     {
  99.         hRASAPI = LoadLibrary("RASAPI32.dll");
  100.         if(hRASAPI)
  101.         {
  102.             (FARPROC)RasEnumConnections =
  103.                 GetProcAddress(hRASAPI, "RasEnumConnectionsA");
  104.             (FARPROC)RasGetConnectStatus =
  105.                 GetProcAddress(hRASAPI, "RasGetConnectStatusA");
  106.             if(RasEnumConnections == NULL || RasGetConnectStatus == NULL)
  107.             {
  108.                 FreeLibrary(hRASAPI); hRASAPI = NULL;
  109.             }
  110.         }
  111.     }
  112.     
  113.     // register a window class and create
  114.     wndclass.style         = 0;
  115.     wndclass.lpfnWndProc   = SNTPWndProc;
  116.     wndclass.cbClsExtra    = 0;
  117.     wndclass.cbWndExtra    = 0;
  118.     wndclass.hInstance     = hInst;
  119.     wndclass.hIcon         = NULL;
  120.     wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  121.     wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  122.     wndclass.lpszMenuName  = NULL;
  123.     wndclass.lpszClassName = classname;
  124.     RegisterClass(&wndclass);
  125.     hwndSNTP = CreateWindow(classname, "TClockSNTP",
  126.         WS_CHILD, 0, 0, 0, 0,
  127.         hwndParent, (HMENU)1, hInst, NULL);
  128.     
  129.     hwndSNTPLog = CreateWindowEx(WS_EX_CLIENTEDGE, "listbox", "",
  130.         WS_CHILD|WS_VSCROLL|WS_TABSTOP,
  131.         0, 0, 0, 0,
  132.         hwndSNTP, (HMENU)1, hInst, NULL);
  133.     
  134.     InitSyncTimeSetting();
  135.     
  136.     return TRUE;
  137. }
  138.  
  139. /*---------------------------------------------------
  140.     window procedure to process WinSock
  141. ---------------------------------------------------*/
  142. LRESULT CALLBACK SNTPWndProc(HWND hwnd, UINT message,
  143.     WPARAM wParam, LPARAM lParam)
  144. {
  145.     switch(message)
  146.     {
  147.         case WSOCK_GETHOST: // get IP address
  148.             OnGetHost(hwnd, wParam, lParam);
  149.             return 0;
  150.         case WSOCK_SELECT:  // receive SNTP data
  151.             OnReceive(hwnd, wParam, lParam);
  152.             return 0;
  153.         case (WM_USER + 10):  // command to start
  154.             SNTPStart(hwnd, (char*)lParam);
  155.             return 0;
  156.     }
  157.     
  158.     return DefWindowProc(hwnd, message, wParam, lParam);
  159. }
  160.  
  161. /*---------------------------------------------------
  162.     if RASAPI.dll exists
  163. ---------------------------------------------------*/
  164. BOOL IsRASAPI(void)
  165. {
  166.     return (hRASAPI != NULL);
  167. }
  168.  
  169. /*---------------------------------------------------
  170.     load settings for time syncronizing
  171. ---------------------------------------------------*/
  172. void InitSyncTimeSetting(void)
  173. {
  174.     char section[] = "SNTP";
  175.     char s[80];
  176.     
  177.     bSyncTimer = GetMyRegLong(section, "Timer", FALSE);
  178.     bSyncADay = GetMyRegLong(section, "ADay", TRUE);
  179.     nMinutes = GetMyRegLong(section, "Minutes", 60);
  180.     bNoDial = FALSE;
  181.     if(hRASAPI)
  182.         bNoDial = GetMyRegLong(section, "NoDial", TRUE);
  183.     nLastDay = GetMyRegLong(section, "LastDay", -1);
  184.     
  185.     GetMyRegStr(section, "Begin", s, 80, "");
  186.     if(s[0])
  187.     {
  188.         time2int(&nHourStart, &nMinuteStart, s);
  189.         GetMyRegStr(section, "End", s, 80, "");
  190.         if(s[0])
  191.             time2int(&nHourEnd, &nMinuteEnd, s);
  192.         else nHourStart = nMinuteStart = -1;
  193.     }
  194. }
  195.  
  196. /*-------------------------------------------
  197.     called from main window procedure.
  198.     clean up
  199. ---------------------------------------------*/
  200. void EndSyncTime(HWND hwnd)
  201. {
  202.     hwnd = GetDlgItem(hwnd, 1);
  203.     
  204.     SocketClose(hwnd, NULL);
  205.     
  206.     if(hRASAPI) FreeLibrary(hRASAPI);
  207.     hRASAPI = NULL;
  208.     
  209.     WSACleanup();
  210. }
  211.  
  212. /*------------------------------------------------
  213.     called when main window received WM_TIMER.
  214.     determine to start or not every second.
  215. --------------------------------------------------*/
  216. void OnTimerSNTP(HWND hwnd, SYSTEMTIME* st)
  217. {
  218.     BOOL bDo = FALSE;
  219.     
  220.     if(bSendingData) // while sending/receiving
  221.     {
  222.         char msg[80];
  223.         DWORD dif;
  224.         dif = GetTickCount() - dwTickCountOnSend;
  225.         if(dif >= (DWORD)nTimeout)  // check timeout
  226.         {
  227.             wsprintf(msg, "timeout (%04d)", dif);
  228.             SocketClose(GetDlgItem(hwnd, 1), msg);
  229.         }
  230.         return;
  231.     }
  232.     
  233.     if(g_hGetHost) // while getting host address
  234.     {
  235.         DWORD dif;
  236.         dif = GetTickCount() - dwTickCountOnGetHost;
  237.         if(dif >= 10000)
  238.         {
  239.             SocketClose(GetDlgItem(hwnd, 1),
  240.                 "failed to get IP address");
  241.         }
  242.         return;
  243.     }
  244.     
  245.     if(!bSyncTimer) return;
  246.     
  247.     if(g_socket != -1 || g_hGetHost != NULL) return;
  248.     
  249.     if(nHourStart >= 0)
  250.     {
  251.         if((nHourStart <= nHourEnd && 
  252.                 (nHourStart <= st->wHour && st->wHour <= nHourEnd)) ||
  253.            (nHourStart > nHourEnd && 
  254.                 (nHourStart <= st->wHour || st->wHour <= nHourEnd)))
  255.         {
  256.             if(st->wHour == nHourStart &&
  257.                 st->wMinute < nMinuteStart) return;
  258.             if(st->wHour == nHourEnd &&
  259.                 nMinuteEnd < st->wMinute) return;
  260.         }
  261.         else return;
  262.     }
  263.     
  264.     if(bSyncADay)
  265.     {
  266.         if(st->wDay != nLastDay)
  267.         {
  268.             if(!bNoDial || IsConnecting()) bDo = TRUE;
  269.         }
  270.     }
  271.     else
  272.     {
  273.         if(bFirst || 
  274.             (GetTickCount()-dwTickCount >= (DWORD)nMinutes*60*1000))
  275.         {
  276.             if(!bNoDial || (st->wMinute != nLastMinute && IsConnecting()))
  277.                 bDo = TRUE;
  278.         }
  279.     }
  280.     nLastMinute = st->wMinute;
  281.     
  282.     if(bDo)
  283.         StartSyncTime(hwnd, NULL, 0);
  284. }
  285.  
  286. /*---------------------------------------------------
  287.     check RAS connection
  288. ---------------------------------------------------*/
  289. BOOL IsConnecting(void)
  290. {
  291.     RASCONN rc;
  292.     RASCONNSTATUS rcs;
  293.     DWORD cb, cConnections;
  294.     
  295.     if(!hRASAPI) return FALSE;
  296.     
  297.     memset(&rc, 0, sizeof(rc));
  298.     rc.dwSize = sizeof(rc);
  299.     cb = sizeof(rc);
  300.     if(RasEnumConnections(&rc, &cb, &cConnections) == 0 &&
  301.         cConnections > 0)
  302.     {
  303.         memset(&rcs, 0, sizeof(rcs));
  304.         rcs.dwSize = sizeof(rcs);
  305.         if(RasGetConnectStatus(rc.hrasconn, &rcs) == 0 &&
  306.             rcs.rasconnstate == RASCS_Connected) return TRUE;
  307.     }
  308.     return FALSE;
  309. }
  310.  
  311. /*---------------------------------------------------
  312.     command to start syncronizing
  313. ---------------------------------------------------*/
  314. void StartSyncTime(HWND hwndParent, char* pServer, int nto)
  315. {
  316.     HWND hwnd;
  317.     SYSTEMTIME st;
  318.     char section[] = "SNTP";
  319.     char server[80], s[80];
  320.     
  321.     if(g_socket != -1 || g_hGetHost != NULL) return;
  322.     
  323.     if(pServer == NULL || *pServer == 0)
  324.     {
  325.         GetMyRegStr(section, "Server", server, 80, "");
  326.         pServer = server;
  327.     }
  328.     if(nto == 0)
  329.         nto = GetMyRegLong(section, "Timeout", 1000);
  330.     
  331.     if(*pServer == 0) return;
  332.     hwnd = GetDlgItem(hwndParent, 1);
  333.     if(!hwnd) return;
  334.     
  335.     nMinuteDif = 0;
  336.     GetMyRegStr(section, "Dif", s, 80, "");
  337.     if(s[0])
  338.     {
  339.         int h, m;
  340.         time2int(&h, &m, s);
  341.         nMinuteDif = h * 60 + m;
  342.     }
  343.     
  344.     GetLocalTime(&st);
  345.     nLastDay = st.wDay;
  346.     SetMyRegLong(section, "LastDay", nLastDay);
  347.     dwTickCount = GetTickCount();
  348.     bFirst = FALSE;
  349.     
  350.     nTimeout = nto;
  351.     
  352.     SNTPStart(hwnd, pServer);
  353. }
  354.  
  355. /*---------------------------------------------------
  356.     start SNTP session
  357. ---------------------------------------------------*/
  358. void SNTPStart(HWND hwnd, char *buf)
  359. {
  360.     char servername[256];
  361.     unsigned long serveraddr;
  362.     
  363.     if(g_socket != -1 || g_hGetHost != NULL) return;
  364.     
  365.     // get server name and port
  366.     g_port = GetServerPort(buf, servername);
  367.     if(g_port == -1)
  368.     {
  369.         Log("invalid server name"); return;
  370.     }
  371.     
  372.     // make a socket
  373.     g_socket = socket(PF_INET, SOCK_DGRAM, 0);
  374.     if(g_socket == INVALID_SOCKET)
  375.     {
  376.         Log("socket() failed");
  377.         g_socket = -1; return;
  378.     }
  379.     
  380.     serveraddr = inet_addr((char*)servername);
  381.     // if server name is not "XXX.XXX.XXX.XXX"
  382.     if(serveraddr == -1)
  383.     {
  384.         // request IP address
  385.         g_pGetHost = malloc(MAXGETHOSTSTRUCT);
  386.         g_hGetHost = WSAAsyncGetHostByName(hwnd, WSOCK_GETHOST,
  387.             servername, g_pGetHost, MAXGETHOSTSTRUCT);
  388.         if(g_hGetHost == 0)
  389.         {
  390.             SocketClose(hwnd, "WSAAsyncGetHostByName() failed");
  391.             return;
  392.         }
  393.         dwTickCountOnGetHost = GetTickCount();
  394.         return;
  395.     }
  396.     
  397.     // send data
  398.     SNTPSend(hwnd, serveraddr);
  399. }
  400.  
  401. /*---------------------------------------------------
  402.     called when the window received WSOCK_GETHOST.
  403.     get IP address and send data.
  404. ---------------------------------------------------*/
  405. void OnGetHost(HWND hwnd, WPARAM wParam, LPARAM lParam)
  406. {
  407.     struct hostent *pHostEnt;
  408.     unsigned long serveraddr;
  409.     
  410.     if(g_hGetHost == NULL) return;
  411.     
  412.     // success ?
  413.     if(WSAGETASYNCERROR(lParam) != 0)
  414.     {
  415.         SocketClose(hwnd, "failed to get IP address");
  416.         return;
  417.     }
  418.     
  419.     // valid handle ?
  420.     if(g_hGetHost != (HANDLE)wParam) return;
  421.     
  422.     // get IP address
  423.     pHostEnt = (struct hostent *)g_pGetHost;
  424.     serveraddr =  *((unsigned long *)((pHostEnt->h_addr_list)[0]));
  425.     free(g_pGetHost); g_pGetHost = NULL;
  426.     g_hGetHost = NULL;
  427.     
  428.     // send data
  429.     SNTPSend(hwnd, serveraddr);
  430. }
  431.  
  432. /*---------------------------------------------------
  433.     send SNTP data
  434. ---------------------------------------------------*/
  435. void SNTPSend(HWND hwnd, unsigned long serveraddr)
  436. {
  437.     struct sockaddr_in serversockaddr;
  438.     struct NTP_Packet NTP_Send;
  439.     
  440.     // request notification of events
  441.     if(WSAAsyncSelect(g_socket, hwnd, WSOCK_SELECT, FD_READ) == SOCKET_ERROR)
  442.     {
  443.         SocketClose(hwnd, "WSAAsyncSelect() failed");
  444.         return;
  445.     }
  446.     
  447.     // set IP address and port
  448.     serversockaddr.sin_family = AF_INET;
  449.     serversockaddr.sin_addr.s_addr = serveraddr;
  450.     serversockaddr.sin_port = htons((unsigned short)g_port);
  451.     memset(serversockaddr.sin_zero,(int)0,sizeof(serversockaddr.sin_zero));
  452.     
  453.     // init a packet
  454.     memset(&NTP_Send, 0, sizeof(struct NTP_Packet));
  455.     NTP_Send.Control_Word = htonl(0x0B000000);
  456.     
  457.     // send a packet
  458.     if(sendto(g_socket, (const char *)&NTP_Send, sizeof(NTP_Send), 0, 
  459.         (struct sockaddr *)&serversockaddr,
  460.         sizeof(serversockaddr)) == SOCKET_ERROR)
  461.     {
  462.         SocketClose(hwnd, "sendto() failed");
  463.         return;
  464.     }
  465.     
  466.     
  467.     // save tickcount
  468.     dwTickCountOnSend = GetTickCount();
  469.     bSendingData = TRUE;
  470. }
  471.  
  472. /*---------------------------------------------------
  473.     called when the window received WSOCK_SELECT.
  474.     receive SNTP data and set time.
  475. ---------------------------------------------------*/
  476. void OnReceive(HWND hwnd, WPARAM wParam, LPARAM lParam)
  477. {
  478.     struct sockaddr_in serversockaddr;
  479.     struct NTP_Packet NTP_Recv;
  480.     int sockaddr_Size;
  481.     
  482.     if(g_socket == -1) return;
  483.     if(WSAGETSELECTERROR(lParam))
  484.     {
  485.         SocketClose(hwnd, "failed to receive");
  486.         return;
  487.     }
  488.     if(g_socket != (int)wParam ||
  489.         WSAGETSELECTEVENT(lParam) != FD_READ) return;
  490.     
  491.     // receive data
  492.     sockaddr_Size = sizeof(serversockaddr);
  493.     if(recvfrom(g_socket, (char *)&NTP_Recv, sizeof(NTP_Recv), 0,
  494.         (struct sockaddr *)&serversockaddr, &sockaddr_Size) == SOCKET_ERROR)
  495.     {
  496.         SocketClose(hwnd, "recvfrom() failed");
  497.         return;
  498.     }
  499.     
  500.     // set system time
  501.     SynchronizeSystemTime(ntohl(NTP_Recv.transmit_timestamp_seconds),
  502.         ntohl(NTP_Recv.transmit_timestamp_fractions));
  503.     
  504.     // close socket
  505.     SocketClose(hwnd, NULL);
  506. }
  507.  
  508. /*---------------------------------------------------
  509.     set system time to received data
  510. ---------------------------------------------------*/
  511. void SynchronizeSystemTime(DWORD seconds, DWORD fractions)
  512. {
  513.     FILETIME ft, ftold;
  514.     SYSTEMTIME st, st_dif, lt;
  515.     char s[1024];
  516.     DWORD sr_time;
  517.     DWORDLONG dif;
  518.     BOOL b;
  519.     
  520.     // timeout ?
  521.     sr_time = GetTickCount() - dwTickCountOnSend;
  522.     if(sr_time >= (DWORD)nTimeout)
  523.     {
  524.         wsprintf(s, "timeout (%04d)", sr_time);
  525.         Log(s); return;
  526.     }
  527.     
  528.     // current time
  529.     GetSystemTimeAsFileTime(&ftold);
  530.     
  531.     // NTP data -> FILETIME
  532.     *(DWORDLONG*)&ft =
  533.         // seconds from 1900/01/01 → 100 nano-seconds from 1601/01/01
  534.         M32x32to64(seconds, 10000000) + 94354848000000000i64;
  535.     
  536.     // difference
  537.     if(nMinuteDif > 0)
  538.         *(DWORDLONG*)&ft += M32x32to64(nMinuteDif * 60, 10000000);
  539.     else if(nMinuteDif < 0)
  540.         *(DWORDLONG*)&ft -= M32x32to64(-nMinuteDif * 60, 10000000);
  541.     
  542.     // set system time
  543.     b = FileTimeToSystemTime(&ft, &st);
  544.     if(b)
  545.     {
  546.         // 200 pico-seconds -> milli-seconds
  547.         st.wMilliseconds = (WORD)(fractions / 5000000);
  548.         b = SetSystemTime(&st);
  549.     }
  550.     if(!b)
  551.     {
  552.         Log("failed to set time"); return;
  553.     }
  554.     
  555.     GetLocalTime(<);
  556.     nLastDay = lt.wDay;
  557.     SetMyRegLong("SNTP", "LastDay", nLastDay);
  558.     
  559.     SystemTimeToFileTime(&st, &ft);
  560.     // delayed or advanced
  561.     b = (*(DWORDLONG*)&ft > *(DWORDLONG*)&ftold);
  562.     // get difference
  563.     if(b) dif = *(DWORDLONG*)&ft - *(DWORDLONG*)&ftold;
  564.     else  dif = *(DWORDLONG*)&ftold - *(DWORDLONG*)&ft;
  565.     FileTimeToSystemTime((FILETIME*)&dif, &st_dif);
  566.     
  567.     // save log
  568.     strcpy(s, "synchronized ");
  569.     if(st_dif.wYear == 1601 && st_dif.wMonth == 1 &&
  570.         st_dif.wDay == 1 && st_dif.wHour == 0)
  571.     {
  572.         strcat(s, b?"+":"-");
  573.         wsprintf(s + strlen(s), "%02d:%02d.%03d ",
  574.             st_dif.wMinute, st_dif.wSecond, st_dif.wMilliseconds);
  575.     }
  576.     wsprintf(s + strlen(s), "(%04d)", sr_time);
  577.     Log(s);
  578.     
  579.     GetMyRegStr("SNTP", "Sound", s, 1024, "");
  580.     PlayFile(hwndMain, s, 0);
  581. }
  582.  
  583. /*---------------------------------------------------
  584.     close a socket
  585. ---------------------------------------------------*/
  586. void SocketClose(HWND hwnd, const char *msgbuf)
  587. {
  588.     // cancel task handle of WSAAsyncGetHostByName()
  589.     if(g_hGetHost != NULL) WSACancelAsyncRequest(g_hGetHost);
  590.     g_hGetHost = NULL;
  591.     // free memory
  592.     if(g_pGetHost) free(g_pGetHost);
  593.     g_pGetHost = NULL;
  594.     
  595.     if(g_socket != -1)
  596.     {
  597.         // cancel request of notification
  598.         WSAAsyncSelect(g_socket, hwnd, 0, 0);
  599.         // close socket
  600.         closesocket(g_socket);
  601.     }
  602.     g_socket = -1;
  603.     bSendingData = FALSE;
  604.     
  605.     if(msgbuf) Log(msgbuf);
  606. }
  607.  
  608. /*---------------------------------------------------
  609.     get server name and port number from string
  610.         buf: "ntp.xxxxx.ac.jp:123"
  611. ---------------------------------------------------*/
  612. int GetServerPort(const char *buf, char *server)
  613. {
  614.     char *p;
  615.     int port = 123;
  616.  
  617.     if(strcmp(buf,"") == 0) return -1;
  618.     strcpy(server, buf);
  619.     
  620.     for(p = server; *p != ':' && *p != '\0'; p++);
  621.     if(*p == ':')
  622.     {
  623.         *p = 0; p++; port = 0;
  624.         while(*p)
  625.         {
  626.             if('0' <= *p && *p <= '9')
  627.                 port = port * 10 + *p - '0';
  628.             else
  629.             {
  630.                 port = -1; break;
  631.             }
  632.             p++;
  633.         }
  634.     }
  635.     return port;
  636. }
  637.  
  638. /*-------------------------------------------
  639.     save log data
  640. ---------------------------------------------*/
  641. void Log(const char* msg)
  642. {
  643.     SYSTEMTIME st;
  644.     char s[160];
  645.     int count, index;
  646.     
  647.     GetLocalTime(&st);
  648.     wsprintf(s, "%02d/%02d %02d:%02d:%02d ",
  649.         st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
  650.     strcat(s, msg);
  651.     
  652.     // save to listbox
  653.     count = SendMessage(hwndSNTPLog, LB_GETCOUNT, 0, 0);
  654.     if(count > 100)
  655.         SendMessage(hwndSNTPLog, LB_DELETESTRING, 0, 0);
  656.     index = SendMessage(hwndSNTPLog, LB_ADDSTRING, 0, (LPARAM)s);
  657.     SendMessage(hwndSNTPLog, LB_SETCURSEL, index, 0);
  658.     
  659.     // save to file
  660.     if(GetMyRegLong("SNTP", "SaveLog", TRUE))
  661.     {
  662.         HFILE hf;
  663.         char fname[MAX_PATH];
  664.         
  665.         strcpy(fname, mydir);
  666.         add_title(fname, "SNTP.txt");
  667.         hf = _lopen(fname, OF_WRITE);
  668.         if(hf == HFILE_ERROR)
  669.             hf = _lcreat(fname, 0);
  670.         if(hf == HFILE_ERROR) return;
  671.         _llseek(hf, 0, 2);
  672.         _lwrite(hf, s, lstrlen(s));
  673.         _lwrite(hf, "\x0d\x0a", 2);
  674.         _lclose(hf);
  675.     }
  676. }
  677.  
  678. /*-------------------------------------------
  679.     "XX:XX" -> two integers
  680. ---------------------------------------------*/
  681. void time2int(int* ph, int* pm, const char* src)
  682. {
  683.     const char* p;
  684.     BOOL bminus;
  685.     
  686.     p = src;
  687.     *ph = 0; *pm = 0;
  688.     bminus = FALSE;
  689.     if(*p == '-') { p++; bminus = TRUE; }
  690.     while('0' <= *p && *p <='9')
  691.         *ph = *ph * 10 + *p++ - '0';
  692.     if(bminus) *ph *= -1;
  693.     if(*p == ':') p++; else return;
  694.     while('0' <= *p && *p <='9')
  695.         *pm = *pm * 10 + *p++ - '0';
  696.     if(bminus) *pm *= -1;
  697. }
  698.