home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / winsock / wstim101 / src / netwrkm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  27.8 KB  |  1,139 lines

  1. // Contents ---------------------------------------------------------------
  2. //
  3. //   netwrkm.c -- Networking functions for NTime
  4. //
  5. //   Version 1.0.1, a Windows Socket Time Client
  6. //
  7. //   Copyright (C) Frederick W. Bent 1994
  8. //   All rights reserved.
  9. //
  10. //
  11. // Redistribution and use in source and binary forms are permitted provided
  12. // that the above copyright notice and this paragraph are duplicated in all
  13. // such forms and that any documentation, advertising materials, and other
  14. // materials related to such distribution and use acknowledge that the
  15. // software was developed by Frederick W. Bent.  In addition, if you wish
  16. // to distribute this program in source and/or binary forms with other
  17. // samples of WinSock programs, you must first contact the author so that
  18. // I can keep accurate records of its usage.  The name of the author may
  19. // not be used to endorse or promote products derived from this software
  20. // without specific prior written permission. Specifically, do not modify
  21. // this source in any way and re-distribute it without the author's prior
  22. // consent.  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OF
  23. // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
  24. // OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  25. //
  26. //
  27. // Description
  28. //
  29. //     Module NETWRKM uses Windows Sockets asynchronous (message based)
  30. //    calls to query a remote time server for the current time.
  31. //     Module NTIME initiates the operation by calling FingerStart(), and
  32. //     NETWRKM signals completion by calling TimeFinish(). NETWRKM uses
  33. //    DSPLIST functions to send the retrieved data to the NTIME user
  34. //    interface module.
  35. //
  36. // Ends -------------------------------------------------------------------
  37.  
  38.  
  39. // Legal Stuff --------------------------------------------------------------
  40. //
  41. // Finger Version 3.1, a Windows Sockets Time Client
  42. //
  43. // Copyright 1992, 1993 Network Research Corporation
  44. //
  45. // Permission to use, modify, and distribute this software and its
  46. // documentation for any purpose and without fee is hereby granted, provided
  47. // that the above copyright notice appears in all copies and that both
  48. // that copyright notice and this permission notice appear in supporting
  49. // documentation.  NRC makes no claims as to the suitability of this software
  50. // for any purpose.
  51. //
  52. // Ends ---------------------------------------------------------------------
  53.  
  54. // History ------------------------------------------------------------------
  55. //
  56. // Aug 17 1994 FWB    Added State = STATE_RECEIVING so UDP will work
  57. //
  58. // Ends ---------------------------------------------------------------------
  59.  
  60. #pragma warn -par
  61.  
  62. // Interface Dependencies -------------------------------------------------
  63.  
  64. #define STRICT
  65.  
  66. #include <windows.h>
  67. #include <windowsx.h>
  68.  
  69. #include <winsock.h>
  70. #include <stdlib.h>
  71. #include <memory.h>
  72. #include <string.h>
  73. #include <time.h>
  74. #include "dsplist.h"
  75. #include "ntime.h"
  76.  
  77. #define    ID_TIMER    1
  78.  
  79. /* Network window class name */
  80. #define NETWINDOW    "WSNTime.NetWindow"
  81.  
  82. // messages for windows sockets returns
  83.  
  84. #define WM_SERVICE            (WM_USER + 1)
  85. #define WM_HOSTRESOLVED       (WM_USER + 2)
  86. #define WM_CONNECTED          (WM_USER + 3)
  87. #define WM_OKTORECV           (WM_USER + 4)
  88.  
  89.  
  90. // Type definitions ------------------------------------------------------
  91.  
  92. enum tagClientState
  93. {
  94.     STATE_SERVICE
  95.       , STATE_RESOLVE
  96.       , STATE_CONNECTING
  97.       , STATE_SENDING
  98.       , STATE_RECEIVING
  99.       , STATE_FINISHED
  100.       , STATE_CLOSING
  101.       , STATE_WSERROR
  102. };
  103.  
  104. typedef enum tagClientState ClientState;
  105.  
  106.  
  107. // Function prototypes ---------------------------------------------------
  108.  
  109. LRESULT CALLBACK NetWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  110. LRESULT DoResolveHost(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  111. LRESULT DoConnect(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  112. LRESULT DoQuery(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  113. LRESULT DoRetrieval(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
  114. LRESULT DoNetClose(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  115. LRESULT DoTimer(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  116. LRESULT DoNetDestroy(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  117. void LoadEntBuf(IPA ipa);
  118.  
  119.  
  120. BOOL    HandleLargeTimeout(void);
  121. void    rtt_init(void);
  122. void     rtt_newpack(void);
  123. int    rtt_start(void);
  124. void    rtt_stop(void);
  125. BOOL    rtt_timeout(void);
  126. BOOL    rtt_register(int timeout);
  127. BOOL    UDPSend(SOCKET sSocket);
  128.  
  129.  
  130. // Global variables -------------------------------------------------------
  131.  
  132. DECODEWORD netMsgs[] =                 // network window messages & handlers
  133. {
  134.      {WM_SERVICE,       DoResolveHost}
  135.    , {WM_HOSTRESOLVED,  DoConnect}
  136.    , {WM_CONNECTED,     DoQuery}
  137.    , {WM_OKTORECV,      DoRetrieval}
  138.    , {WM_TIMER,            DoTimer}
  139.    , {WM_CLOSE,            DoNetClose}
  140.    , {WM_DESTROY,    DoNetDestroy}
  141. };
  142.  
  143.  
  144. /* Maybe in the next release we will allow MULTIPLE connections...
  145. struct tagCLIENT
  146. {
  147.     SOCKET    sSocket;
  148.     HANDLE    hRequest;
  149.     BOOL    bTCPConnection;
  150.     char    szRemoteHost[MAXHOST+1];
  151.     int    Port;
  152.     int    timo;
  153.     long    temptime;
  154.     ClientState State;
  155. };
  156. typedef struct tagCLIENT CLIENT;
  157. */
  158.  
  159. char    szRemoteHost[MAXHOST+1];
  160. SOCKET  sSocket;                      // connects to remote server's socket
  161. HANDLE    hRequest;                 // Async request handle
  162. int     Port;                         // hold port for finger service
  163.  
  164. char    EntBuf[MAXGETHOSTSTRUCT];     // buf for service & resolve returns
  165. HWND    hNetWnd;                      // network window handle
  166. HWND    hMainWnd;
  167. time_t    addminutes;
  168. int    timo;
  169. int    nTCPTimeOutValue;
  170. int    nUDPTimeOutValue;
  171. int    nUDPNumberRetry;
  172. unsigned long    temptime;
  173.  
  174. ClientState    State;
  175.  
  176. //
  177. // InitNetApp -- registers window class for the network module's invisible
  178. // child window. This is called only for the first instance of finger.
  179. //
  180. VOID InitNetApp(VOID)
  181. {
  182.    WNDCLASS wndclass;
  183.  
  184.    wndclass.style         = 0;
  185.    wndclass.lpfnWndProc   = NetWndProc;
  186.    wndclass.cbClsExtra    = 0;
  187.    wndclass.cbWndExtra    = 0;
  188.    wndclass.hInstance     = hInst;
  189.    wndclass.hIcon         = 0;
  190.    wndclass.hCursor       = 0;
  191.    wndclass.hbrBackground = 0;
  192.    wndclass.lpszMenuName  = NULL;
  193.    wndclass.lpszClassName = NETWINDOW;
  194.  
  195.    RegisterClass(&wndclass);
  196. }
  197.  
  198. //
  199. // InitNetInst -- initializes the network module by creating an invisible
  200. // child of the main finger window which will be used to receive Windows
  201. // Sockets notification messages.  The window will be automatically
  202. // destroyed when the main window exits, so no finalization is required.
  203. //
  204. BOOL InitNetInst(HWND hWnd, int nTCPTimeOut, int nUDPTimeOut, int nUDPRetry)
  205. {
  206.    hMainWnd = hWnd;
  207.    nTCPTimeOutValue = ( nTCPTimeOut > 65 ) ? 65 : nTCPTimeOut;
  208.    nUDPTimeOutValue = nUDPTimeOut;
  209.    nUDPNumberRetry = nUDPRetry;
  210.  
  211.    timo = 0;
  212.    temptime = 0L;
  213.  
  214.    sSocket = INVALID_SOCKET;
  215.    hRequest = 0;
  216.  
  217.    hNetWnd = CreateWindow( NETWINDOW, NULL
  218.                , WS_CHILD
  219.             , CW_USEDEFAULT, CW_USEDEFAULT
  220.             , CW_USEDEFAULT, CW_USEDEFAULT
  221.             , hWnd
  222.             , NULL
  223.             , hInst
  224.             , NULL);
  225.  
  226.    if (hNetWnd == NULL) return(FALSE);
  227.  
  228.    return(TRUE);
  229. }
  230.  
  231.  
  232.  
  233. /* Notes:
  234.  * The time is the number of seconds since 00:00 (midnight) 1 January 1900
  235.  * GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
  236.  * base will serve until the year 2036.
  237.  *
  238.  * For example:
  239.  *
  240.  *     2,208,988,800L corresponds to 00:00  1 Jan 1970 GMT, start of UNIX time
  241.  *
  242.  */
  243.  
  244. #define BASE_TIME 2208988800L
  245.  
  246. void    UpdateTime( unsigned long newtime )
  247. {
  248.    struct tm    *tmClock;
  249.    time_t    tClock;
  250.    time_t    tOldTime;
  251.    char        szTemp[256];
  252.    HDC        hdc;
  253.  
  254.  
  255.    /* If we actually did get a response from the remote host */
  256.    if ( newtime != 0 )
  257.    {
  258.     /*
  259.      * Borland C++ 3.1 funtion which will read the
  260.      * TZ=EST5EDT environment variable
  261.      */
  262.     tzset();
  263.  
  264.  
  265.     tClock = newtime - BASE_TIME + addminutes;    /* now in UNIX format */
  266.     if (bUpdateSystemTime) stime(&tClock);
  267.     else tClock -= addminutes;
  268.     tOldTime = time(NULL);
  269.  
  270.     tmClock = localtime(&tClock);
  271.     if ( !strftime(szTemp, sizeof(szTemp), "%a %b %d %H:%M:%S %Y %Z", tmClock))
  272.     {
  273.         /* remove the newline character from the string */
  274.         lstrcpy((LPSTR) szTemp, (LPSTR)asctime(tmClock));
  275.         szTemp[lstrlen((LPSTR)szTemp)-1] = '\0';
  276.     }
  277.  
  278.     hdc = GetDC(hMainWnd);
  279.     if (bUpdateSystemTime)
  280.     {
  281.  
  282.         WinPrintf( hdc, -1, 0, "System time set to %s", (LPSTR) szTemp );
  283.         } else
  284.         WinPrintf( hdc, -1, 0, "Time from host using %s/IP = %s"
  285.                 , (LPSTR) (bShouldUseTCP ? "TCP" : "UDP" )
  286.                 , (LPSTR) szTemp );
  287.     WinPrintf( hdc, -1, 0, "The difference is %0ld seconds", (long)(tOldTime - tClock) );
  288.     ReleaseDC(hMainWnd, hdc);
  289.    } else {
  290.     LoadString(hInst, FE_INVLDTIME, (LPSTR)szTemp, sizeof(szTemp));
  291.     
  292.     MessageBeep(MB_ICONEXCLAMATION);
  293.     MessageBox(hMainWnd, (LPSTR) szTemp, szAppName,
  294.                 MB_ICONEXCLAMATION | MB_OK );
  295.  
  296.     hdc = GetDC(hMainWnd);
  297.     WinPrintf( hdc, -1, 0, szTemp );
  298.     ReleaseDC(hMainWnd, hdc);
  299.    }
  300. }
  301.  
  302.  
  303. void    CancelRequest(HANDLE hRequest)
  304. {
  305.     int    err;
  306.  
  307.     if (hRequest == 0) return;
  308.  
  309.     err = WSACancelAsyncRequest(hRequest);
  310.     hRequest = 0;
  311.  
  312.     if (err == SOCKET_ERROR)
  313.     {
  314.         err = WSAGetLastError();
  315.         if ((err == WSAEALREADY) || (err == WSAEINVAL)) return;
  316.         ReportFingerErr(FE_CANCEL, err);
  317.     }
  318.     return;
  319. }
  320.  
  321.  
  322. void    NetClose(void)
  323. {
  324.     SendMessage(hNetWnd, WM_CLOSE, 0, 0L);
  325. }
  326.  
  327.  
  328. void    CloseTheSocket(SOCKET sSock)
  329. {
  330.     int    err;
  331.     char    szInputBuffer[80];
  332.     int    iInputSize;
  333.  
  334.     if (sSock == INVALID_SOCKET) return;
  335.  
  336.     /* Perform a graceful termination */
  337.     err = shutdown(sSock, 1);    // no sending now
  338.  
  339.     if ( err == SOCKET_ERROR ) {
  340.         ReportFingerErr(FE_SHUTDWN, WSAGetLastError());
  341.     }
  342.  
  343.     State = STATE_CLOSING;
  344.  
  345.     /* Get all remaining data, if any... */
  346.  
  347.     iInputSize = sizeof(szInputBuffer);
  348.     while( (err = recv(sSock, (void FAR *)szInputBuffer, iInputSize, 0)) != 0 )
  349.     {
  350.         if (err == SOCKET_ERROR)
  351.         {
  352.             err = WSAGetLastError();
  353.             if ( err != WSAEWOULDBLOCK )
  354.             {
  355.                 ReportFingerErr(FE_SHUTDWN, err);
  356.             }
  357.     break;
  358.         }
  359.     }
  360.  
  361.     /* turn off all messages, its now a blocking socket */
  362.     err = WSAAsyncSelect(sSock, hNetWnd, 0, 0);
  363.  
  364.     /* now close the socket, will also flush send buffers */
  365.  
  366.     closesocket(sSock);
  367.     sSocket = INVALID_SOCKET;
  368. }
  369.  
  370.  
  371. //
  372. // NetWndProc -- callback function for network window.  The network window
  373. // is a child window created especially to receive windows sockets network
  374. // messages.  The function decodes and routes to appropriate message handler.
  375. //
  376. LRESULT CALLBACK NetWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  377. {
  378.    int i;
  379.  
  380.    for (i = 0; i < dim(netMsgs); i++)
  381.    {
  382.       if (wMsg == netMsgs[i].Code)
  383.      return((*netMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam));
  384.    }
  385.  
  386.    return(DefWindowProc(hWnd, wMsg, wParam, lParam));
  387. }
  388.  
  389.  
  390. //
  391. // FingerStart -- called by FINGER module to initiate a conversation with
  392. // the remote finger server.  We start by resolving the finger tcp service
  393. // to a port number. Windows Sockets WSAAsync routines signal completion
  394. // by posting messages, which are dispatched to appropriate handlers.
  395. //
  396. VOID FingerStart(PSTR szHost)
  397. {
  398.  
  399.    HDC    hdc;
  400.  
  401.    if (strlen(szUser) > 0 )
  402.     addminutes = atol( szUser ); // * 60L;
  403.     else
  404.     addminutes = 0L;
  405.  
  406.    timo = nTCPTimeOutValue;
  407.    State = STATE_CONNECTING;
  408.  
  409.    strcpy(szRemoteHost, szHost);
  410.  
  411.    if (timo > 0)
  412.    {
  413.        /* Generate a WM_TIMER every nTCPTimeOutValue seconds */
  414.        while (!SetTimer(hNetWnd, ID_TIMER, (1000 * timo), NULL))
  415.        {
  416.         if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
  417.                     , szAppName
  418.                     , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  419.         {
  420.                 TimeFinish(FE_ERROR);
  421.             return;
  422.         }
  423.        }
  424.    }
  425.  
  426.    OpenDisplayList();   // new display list will contain received data
  427.  
  428.    hdc = GetDC( hMainWnd );
  429.    WinPrintf( hdc, 1, 0, "Resolving %s...", (LPSTR)szRemoteHost );
  430.    ReleaseDC( hMainWnd, hdc );
  431.  
  432.    State = STATE_SERVICE;
  433.  
  434.    if ((hRequest = WSAAsyncGetServByName(hNetWnd, WM_SERVICE
  435.             , "time", (bShouldUseTCP ? "tcp" : "udp")
  436.             , EntBuf, sizeof(EntBuf))) == 0)
  437.    {
  438.       ReportFingerErr(FE_NOPORT, WSAGetLastError());
  439. //      TimeFinish(FE_ERROR);
  440.       ((SERVENT *) EntBuf)->s_port = htons(IPPORT_TIMESERVER);
  441.    }
  442. }
  443.  
  444.  
  445. VOID    FingerStop(VOID)
  446. {
  447.     if (timo != 0 )
  448.     {
  449.         timo = 0;
  450.         KillTimer(hNetWnd,ID_TIMER);
  451.     }
  452.  
  453.     if (hRequest != 0) CancelRequest(hRequest);
  454.     if (sSocket != INVALID_SOCKET) CloseTheSocket(sSocket);
  455. }
  456.  
  457.  
  458. LRESULT DoNetClose(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  459. {
  460.     KillTimer(hWnd, ID_TIMER);
  461.     CancelRequest(hRequest);
  462.     CloseTheSocket(sSocket);
  463.     return(FALSE);
  464. }
  465.  
  466.  
  467. LRESULT DoNetDestroy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  468. {
  469.     PostQuitMessage(0);
  470.     return(FALSE);
  471. }
  472.  
  473.  
  474. /*
  475.  * If a UDP connection, then see if we should retransmit...
  476.  *
  477.  * For some reason, the Trumpet WinSock rev B6, or rev B10
  478.  * will not indicate a timeout when using a non-blocking
  479.  * STREAM socket, so this is needed to fake a timeout for
  480.  * a TCP connection as well.
  481.  */
  482. LRESULT DoTimer(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  483. {
  484.     HDC    hdc;
  485.  
  486.     KillTimer(hWnd, ID_TIMER);
  487.     timo = 0;
  488.  
  489.     switch(State)
  490.     {
  491. #ifdef    RECOVER_TIMEOUT
  492.     default:
  493.         if (IDRETRY == MessageBox(hMainWnd, "Timeout occurred attempting connection!", szAppName, MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  494.         {
  495.             timo = nTCPTimeOutValue;
  496.             while (!SetTimer(hWnd, ID_TIMER, (1000 * timo), NULL))
  497.             {
  498.                 if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
  499.                             , szAppName
  500.                             , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  501.                 {
  502.                     timo = 0;
  503.                     CancelRequest(hRequest);
  504.                     hdc = GetDC( hMainWnd );
  505.                     WinPrintf( hdc, -1, 0, "Request canceled.");
  506.                     ReleaseDC( hMainWnd, hdc );
  507.                     TimeFinish(FE_ERROR);
  508.                     return(FALSE);
  509.                 }
  510.             }
  511.         } else {
  512.             CancelRequest(hRequest);
  513.             hdc = GetDC( hMainWnd );
  514.             WinPrintf( hdc, -1, 0, "Request canceled." );
  515.             ReleaseDC( hMainWnd, hdc );
  516.             TimeFinish(FE_ERROR);
  517.         }
  518.         break;
  519. #else
  520.     case STATE_SERVICE:
  521.         PostMessage(hWnd, WM_SERVICE, (WPARAM) hRequest, WSAMAKEASYNCREPLY(sizeof(SERVENT),WSAETIMEDOUT));
  522.         break;
  523.  
  524.     case STATE_RESOLVE:
  525.         PostMessage(hWnd, WM_HOSTRESOLVED, (WPARAM) hRequest, WSAMAKEASYNCREPLY(sizeof(HOSTENT),WSAETIMEDOUT));
  526.         break;
  527.  
  528.     case STATE_CONNECTING:
  529.         PostMessage(hWnd, WM_CONNECTED, (WPARAM) sSocket, WSAMAKESELECTREPLY(FD_CONNECT,WSAETIMEDOUT));
  530.         break;
  531. #endif
  532.  
  533.     case STATE_SENDING:
  534.         if (HandleLargeTimeout())
  535.             return(FALSE);
  536.  
  537.         /* UDP Timeout yet? */
  538.         if (!rtt_timeout())
  539.         {
  540.             hdc = GetDC( hMainWnd );
  541.             WinPrintf( hdc, -1, 0, "re-sending UDP datagram" );
  542.             ReleaseDC( hMainWnd, hdc );
  543.  
  544.             /* Resend the packet */
  545.             if (!UDPSend(sSocket))
  546.             {
  547.                 ReportFingerErr(FE_NOSEND, WSAGetLastError());
  548.                 TimeFinish(FE_ERROR);
  549.                 return(FALSE);
  550.             }
  551.  
  552.             timo = rtt_start();
  553.             if (!rtt_register(timo))
  554.             {
  555.                             CancelRequest(hRequest);
  556.                 TimeFinish(FE_ERROR);
  557.                 return(FALSE);
  558.             }
  559.                             
  560.         } else {
  561. #ifdef    RECOVER_TIMEOUT
  562.             if (IDRETRY == MessageBox(hMainWnd, "Timeout occurred waiting for response!", szAppName, MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  563.             {
  564.                 rtt_init();
  565.                 rtt_newpack();
  566.                 if (!UDPSend(sSocket))
  567.                 {
  568.                     ReportFingerErr(FE_NOSEND, WSAGetLastError());
  569.                     TimeFinish(FE_ERROR);
  570.                     return(FALSE);
  571.                 }
  572.  
  573.                 timo = rtt_start();
  574.                 if (timo > 65) timo = 65;
  575.                 while (!SetTimer(hWnd, ID_TIMER, (1000 * timo), NULL))
  576.                 {
  577.                     if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
  578.                                 , szAppName
  579.                                 , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  580.                                     {
  581.                         timo = 0;
  582.                                                 CancelRequest(hRequest);
  583.                         TimeFinish(FE_ERROR);
  584.                         return(FALSE);
  585.                     }
  586.                 }
  587.             } else {
  588.                 CancelRequest(hRequest);
  589.                 TimeFinish(FE_ERROR);
  590.                 return(FALSE);
  591.             }
  592. #else
  593.             PostMessage(hWnd, WM_CONNECTED, sSocket, WSAMAKESELECTREPLY(FD_CONNECT,WSAETIMEDOUT));
  594. #endif
  595.         }
  596.             break;
  597.     }
  598.  
  599.     return(FALSE);
  600. }
  601.  
  602.  
  603. //
  604. // DoResolveHost -- resolves host specifier to an IP address.  Since we
  605. // allow a "dotted decimal" IP address to be entered in lieu of a DNS host
  606. // name, we check for this syntax before assuming a DNS name.
  607. //
  608. LRESULT DoResolveHost(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  609. {
  610.    IPA ipa;
  611.    int err;
  612.  
  613.  
  614.    /* Is this the response to OUR request? */
  615.  
  616.    if ( (HANDLE)wParam != hRequest ) return(FALSE);
  617.  
  618.    if ((err = WSAGETASYNCERROR(lParam)) != 0)
  619.    {
  620.       ReportFingerErr(FE_NOPORT, err);         // cannot locate finger service
  621.       TimeFinish(FE_ERROR);
  622.       return(FALSE);
  623.    }
  624.  
  625.    Port = ntohs(((SERVENT *)EntBuf)->s_port);    // we're going to reuse the buffer
  626.  
  627.    // if host specifier is dotted decimal ip address, resolve right here
  628.    if ((ipa = INET_ADDR(szRemoteHost)) != INADDR_NONE)
  629.    {
  630.       LoadEntBuf(ipa);
  631.       PostMessage(hNetWnd, WM_HOSTRESOLVED, (WPARAM)hRequest, 0L);
  632.       return(FALSE);
  633.    }
  634.  
  635.    State = STATE_RESOLVE;
  636.  
  637.    // assume specifier is DNS host name
  638.    if ((hRequest = WSAAsyncGetHostByName(hNetWnd, WM_HOSTRESOLVED, szRemoteHost, EntBuf, sizeof(EntBuf))) == 0)
  639.    {
  640.       ReportFingerErr(FE_NOHOST, WSAGetLastError());
  641.       TimeFinish(FE_ERROR);
  642.    }
  643.  
  644.    return(FALSE);
  645. }
  646.  
  647. //
  648. // LoadEntBuf -- loads the EntBuf (sufficiently) with a HOSTENT and
  649. // referenced IPA.  This is so we can return IPAs in the same
  650. // manner as a WSAAsync call.
  651. //
  652. void LoadEntBuf(IPA ipa)
  653. {
  654.    LPHOSTENT phe = (LPHOSTENT) EntBuf;
  655.    LPPIPA ppipa = (LPPIPA) (EntBuf + sizeof(HOSTENT));
  656.    LPIPA pipa = (LPIPA) (EntBuf + sizeof(HOSTENT) + sizeof(LPPIPA));
  657.  
  658.    _fmemset(phe, 0, sizeof(HOSTENT));
  659.    phe->h_addr_list = (char FAR * FAR *) ppipa;
  660.    *ppipa = pipa;
  661.    *pipa = ipa;
  662. }
  663.  
  664.  
  665. //
  666. // DoConnect -- Responds to the WM_HOSTRESOLVED message by allocating
  667. // a socket and trying to connect to remote time server.
  668. //
  669. LRESULT DoConnect(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  670. {
  671.    HDC    hdc;
  672.    int    err;
  673.  
  674.  
  675.    /* Is this for us? */
  676.    if ( (HANDLE)wParam != hRequest ) return(FALSE);
  677.  
  678.    if ((err = WSAGETASYNCERROR(lParam)) != 0)
  679.    {
  680.       ReportFingerErr(FE_NOHOST, err);       // could not resolve host name
  681.       TimeFinish(FE_ERROR);
  682.       return(FALSE);
  683.    }
  684.  
  685.    hRequest = 0;
  686.  
  687.    if ((sSocket = socket(AF_INET, (bShouldUseTCP ? SOCK_STREAM : SOCK_DGRAM), 0)) != INVALID_SOCKET )
  688.    {
  689.       SOCKADDR_IN server;
  690.       SOCKADDR_IN client;
  691.       HOSTENT *phe = (HOSTENT *) EntBuf;
  692.       BOOL    bDebug;
  693.  
  694.     bDebug=TRUE;
  695.     setsockopt(sSocket,
  696.             SOL_SOCKET, SO_DEBUG, (char FAR *)&bDebug,
  697.             sizeof(bDebug));
  698.  
  699.       /*
  700.        * Bind the connectionless socket to any port on the client
  701.        */
  702.       if (!bShouldUseTCP)
  703.       {
  704.           memset(&client, 0, sizeof(client));
  705.           client.sin_family = AF_INET;
  706.           client.sin_port = htons(0);
  707.           client.sin_addr.s_addr = htonl(INADDR_ANY);
  708.           if ( bind(sSocket, (LPSOCKADDR)&client, sizeof(client)) == SOCKET_ERROR )
  709.           {
  710.           err = WSAGetLastError();
  711.           ReportFingerErr(FE_NOBIND, err);
  712.           TimeFinish(FE_ERROR);
  713.           return(FALSE);
  714.           }
  715.       }
  716.  
  717.       memset(&server, 0, sizeof(server));
  718.       server.sin_family = AF_INET;
  719.       server.sin_port = htons(Port);
  720.       server.sin_addr = *((IN_ADDR FAR *) *phe->h_addr_list);
  721.  
  722.       hdc = GetDC( hMainWnd );
  723.       WinPrintf( hdc, -1, 0, "Trying %s...", (LPSTR)szRemoteHost );
  724.       ReleaseDC( hMainWnd, hdc );
  725.  
  726.       State = STATE_CONNECTING;
  727.  
  728.       // post message when connect is established
  729.       if ( WSAAsyncSelect(sSocket, hNetWnd, WM_CONNECTED, FD_CONNECT) == SOCKET_ERROR )
  730.       {
  731.     err = WSAGetLastError();
  732.     ReportWSError(err);
  733.     TimeFinish(FE_ERROR);
  734.     return(FALSE);
  735.       }
  736.  
  737.       if (connect(sSocket, (SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
  738.       {
  739.     if ((err = WSAGetLastError()) == WSAEWOULDBLOCK)
  740.     {
  741.           if ( WSAAsyncSelect(sSocket, hNetWnd, WM_CONNECTED, FD_CONNECT) == SOCKET_ERROR )
  742.           {
  743.               err = WSAGetLastError();
  744.         ReportWSError(err);
  745.         TimeFinish(FE_ERROR);
  746.         return(FALSE);
  747.           }
  748.  
  749.     } else {
  750.      State = STATE_WSERROR;
  751.      closesocket(sSocket);        // Not connected, so no need to try later...
  752.      sSocket = INVALID_SOCKET;
  753.      ReportFingerErr(FE_NOCONN, err);
  754.      TimeFinish(FE_ERROR);
  755.      return(FALSE);
  756.         }
  757.       }
  758.  
  759.       /*
  760.        * There is no UDP "connection" so we must fake it...
  761.        */
  762.       if (!bShouldUseTCP)
  763.     PostMessage(hNetWnd, WM_CONNECTED, (WPARAM)sSocket, (LPARAM)WSAMAKESELECTREPLY(FD_CONNECT,0));
  764.  
  765.    }
  766.    else
  767.    {
  768.       State = STATE_WSERROR;
  769.       ReportFingerErr(FE_NOSOCK, WSAGetLastError());
  770.       TimeFinish(FE_ERROR);
  771.    }
  772.  
  773.    return(FALSE);
  774. }
  775.  
  776. //
  777. // DoQuery -- Responds to the FD_CONNECT event by enabling FD_READ
  778. // and FD_CLOSE events
  779. //
  780. LRESULT DoQuery(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  781. {
  782.    HDC    hdc;
  783.    int err;
  784.  
  785.  
  786.    if (State != STATE_CONNECTING) return(FALSE);
  787.  
  788.    if ((err = WSAGETSELECTERROR(lParam)) != 0)
  789.    {
  790.       State = STATE_WSERROR;
  791.       ReportFingerErr(FE_NOCONN, err);       // could not connect to server
  792.       TimeFinish(FE_ERROR);
  793.       return(FALSE);
  794.    }
  795.  
  796.    if ((err = WSAGETSELECTEVENT(lParam)) != FD_CONNECT)
  797.    {
  798.     hdc = GetDC( hMainWnd );
  799.     WinPrintf( hdc, -1, 0, "Huh... Expected a FD_CONNECT (%d)", err );
  800.     ReleaseDC( hMainWnd, hdc );
  801.    }
  802.  
  803.    if ((SOCKET)wParam != sSocket)
  804.    {
  805.     ReportFingerErr(IDS_BRK_WINSOCK, WSABASEERR);
  806. //    TimeFinish(FE_ERROR);
  807.     return(FALSE);
  808.    }
  809.  
  810.     // post message when data is available for read
  811.     if (WSAAsyncSelect(sSocket, hNetWnd, WM_OKTORECV, FD_READ | FD_CLOSE) == SOCKET_ERROR)
  812.     {
  813.     State = STATE_WSERROR;
  814.     err = WSAGetLastError();
  815.     ReportWSError(err);
  816.     TimeFinish(FE_ERROR);
  817.     return(FALSE);
  818.     }
  819.  
  820.     // Send empty message if UPD
  821.     if (!bShouldUseTCP)
  822.     {
  823.     State = STATE_SENDING;
  824.  
  825.     hdc = GetDC( hMainWnd );
  826.     WinPrintf( hdc, -1, 0, "sending UDP datagram" );
  827.     ReleaseDC( hMainWnd, hdc );
  828.  
  829.     KillTimer(hWnd, ID_TIMER);
  830.     rtt_init();
  831.     rtt_newpack();
  832.  
  833.     if (!UDPSend(sSocket))
  834.     {
  835.         ReportFingerErr(FE_NOSEND, WSAGetLastError());
  836.         TimeFinish(FE_ERROR);
  837.         return(FALSE);
  838.     }
  839.  
  840.     /*
  841.      * Start out timeout waiting for response
  842.      */
  843.     timo = rtt_start();
  844.     if (!rtt_register(timo))
  845.         {
  846.         TimeFinish(FE_ERROR);
  847.         return(FALSE);
  848.     }
  849.  
  850.     } else {
  851.         hdc = GetDC( hMainWnd );
  852.         WinPrintf( hdc, -1, 0, "[%s]", (LPSTR)szRemoteHost );
  853.         ReleaseDC( hMainWnd, hdc );
  854.  
  855.         State = STATE_RECEIVING;
  856.     }
  857.  
  858.     return(FALSE);
  859. }
  860.  
  861.  
  862. #define    TVAL_SIZE    4
  863.  
  864. // Network function
  865.  
  866.     LRESULT DoRetrieval(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
  867.  
  868. // Summary ----------------------------------------------------------------
  869. //
  870. //    Handle the FD_READ and FD_CLOSE events.
  871. //
  872. // Parameters
  873. //
  874. //    hWnd    Handle of the window.
  875. //
  876. //    Msg    Message.
  877. //
  878. //    wParam    First message paramter.
  879. //
  880. //    lParam    Second message parameter.
  881. //
  882. //
  883. // Returns
  884. //
  885. //    LRESULT
  886. //
  887. //    Returns FALSE of the dialog message was handled, otherwise TRUE.
  888. //
  889. // Ends -------------------------------------------------------------------
  890.  
  891. {
  892.    unsigned long buf;
  893.    int    nchars;
  894.    int    err;
  895.  
  896.  
  897.  
  898.    if ((err = WSAGETSELECTERROR(lParam)) != 0)
  899.    {
  900.       ReportFingerErr(FE_NOCONN, err);       // could not connect to server
  901.       TimeFinish(FE_ERROR);
  902.       return(FALSE);
  903.    }
  904.  
  905.  
  906.    /* If not for our socket, ignore it... */
  907.    if ((SOCKET)wParam != sSocket)
  908.     return(FALSE);
  909.  
  910.  
  911.    /* receives data not to exceed buf size & reenables notification
  912.       of more data pending FD_READ */
  913.  
  914.    switch(WSAGETSELECTEVENT(lParam))
  915.    {
  916.    case FD_CLOSE:
  917.  
  918.        /* We have gotten the data, so stop the timer */
  919.  
  920.        if ( timo != 0 )
  921.        {
  922.            timo = 0;
  923.            KillTimer(hWnd, ID_TIMER);
  924.        }
  925.  
  926.        if ( State != STATE_CLOSING )
  927.            {
  928.            CloseTheSocket(sSocket);
  929.  
  930.            UpdateTime( temptime );      // Handle the time that we got
  931.  
  932.            CloseDisplayList();            // close list if error or end-of-data
  933.  
  934.            TimeFinish(0);               // signal end-of-finger
  935.        }
  936.        break;
  937.            
  938.    case FD_READ:
  939.        err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_CLOSE);
  940.        if ( err == SOCKET_ERROR )
  941.        {
  942.         State = STATE_WSERROR;
  943.         err = WSAGetLastError();
  944.         ReportWSError(err);
  945.         return(FALSE);
  946.        }
  947.  
  948.        nchars = recv(sSocket, (char FAR *) &buf, TVAL_SIZE, 0);
  949.        if ( nchars == SOCKET_ERROR )
  950.        {
  951.         /*
  952.          * If this would block, then try again
  953.          */
  954.         temptime = 0L;
  955.         err = WSAGetLastError();
  956.         if ( err == WSAEWOULDBLOCK )
  957.         {
  958.             err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_READ | FD_CLOSE);
  959.             if ( err == SOCKET_ERROR )
  960.             {
  961.                 State = STATE_WSERROR;
  962.                 err = WSAGetLastError();
  963.                 CloseTheSocket(sSocket);
  964.                 ReportWSError(err);
  965.             }
  966.             return(FALSE);
  967.         } else {
  968.                     State = STATE_WSERROR;
  969.             CloseTheSocket(sSocket);
  970.             ReportFingerErr(FE_NORECV, err);
  971.         }
  972.        } else {
  973.         if ( ( State == STATE_RECEIVING ) || ( State == STATE_SENDING ) )
  974.                 {
  975.             State = STATE_FINISHED;
  976.                 
  977.             if ( nchars == TVAL_SIZE )
  978.                 {
  979.                 temptime = ntohl( buf );
  980.             } else { // 0 bytes read - service not available
  981.                 temptime = 0L;
  982.             }
  983.         }
  984.        }
  985.  
  986.        err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_READ | FD_CLOSE);
  987.        if ( err == SOCKET_ERROR )
  988.        {
  989.         State = STATE_WSERROR;
  990.         err = WSAGetLastError();
  991.         ReportWSError(err);
  992.         return(FALSE);
  993.        }
  994.  
  995.        if (!bShouldUseTCP)
  996.        {
  997.         rtt_stop();
  998.        }
  999.  
  1000.        /* Fake a closure event */
  1001.        PostMessage(hNetWnd, WM_OKTORECV, (WPARAM)sSocket, (LPARAM)WSAMAKESELECTREPLY(FD_CLOSE,0));
  1002.  
  1003.  
  1004.        break;
  1005.    default:
  1006.        {
  1007.         HDC hdc;
  1008.  
  1009.            err = WSAGETSELECTEVENT(lParam);
  1010.            hdc = GetDC( hMainWnd );
  1011.         WinPrintf( hdc, -1, 0, "Huh... Expected a FD_CONNECT | FD_CLOSE (%d)", err );
  1012.         ReleaseDC( hMainWnd, hdc );
  1013.        }
  1014.            break;
  1015.  
  1016.    }
  1017.  
  1018.    return(FALSE);
  1019. }
  1020.  
  1021.  
  1022. #define    RTT_RXTMIN    2
  1023. #define RTT_RXTSTRT    3
  1024. #define RTT_RXTMAX    (nUDPTimeOutValue)    // 120
  1025. #define RTT_MAXNREXMT    4
  1026. int    exp_backoff[ RTT_MAXNREXMT + 1 ] =
  1027.     { 1, 2, 4, 8, 16 };
  1028. //        0  1  2  3   4
  1029. //    [0] ==    3sec not used    
  1030. //    [1] ==    6sec second retransmission
  1031. //    [2] ==   24sec third retransmission
  1032. //    [3] ==  192sec fourth retransmission
  1033. //    [4] == 3072sec fifth retransmission
  1034. //
  1035. // RTT_RXTMAX is the highest value that will be used for any
  1036. // single retransmission attempt.
  1037. //
  1038. // nUDPNumberRetry will limit the number of retry attempts.
  1039.  
  1040. int    rtt_currto;
  1041. int    rtt_nrexmt;
  1042. int    rtt_tempto;
  1043. int    rtt_totto;
  1044.  
  1045. void    rtt_init(void)
  1046. {
  1047.     rtt_currto = 0;
  1048.     rtt_tempto = 0;
  1049. }
  1050.  
  1051.  
  1052. void     rtt_newpack(void)
  1053. {
  1054.     rtt_nrexmt = 0;
  1055.     rtt_totto = 0;
  1056. }
  1057.  
  1058.  
  1059. int    rtt_start(void)
  1060. {
  1061.     if ( rtt_nrexmt > 0 )
  1062.     {
  1063.         rtt_currto *= exp_backoff[rtt_nrexmt];
  1064.         if ( rtt_currto > RTT_RXTMAX )
  1065.                 {
  1066.             rtt_currto = RTT_RXTMAX;
  1067.             rtt_nrexmt = RTT_MAXNREXMT;    // OK, do not try again...
  1068.         }
  1069.         rtt_tempto = rtt_currto;
  1070.                 return(rtt_currto);
  1071.     }
  1072.  
  1073.     rtt_currto = RTT_RXTSTRT;    // first timeout at RTT_RXTSTRT sec.
  1074.     return (rtt_currto);
  1075. }
  1076.  
  1077.  
  1078. void    rtt_stop(void)
  1079. {
  1080. }
  1081.  
  1082.  
  1083. BOOL    rtt_timeout(void)
  1084. {
  1085.     rtt_stop();
  1086.     if (++rtt_nrexmt > RTT_MAXNREXMT)
  1087.         return(TRUE);
  1088.         return(FALSE);
  1089. }
  1090.  
  1091.  
  1092. BOOL    rtt_register(int timeout)
  1093. {
  1094.     if (timeout > 65) timeout = 65;
  1095.     if (timeout > 0)
  1096.         {
  1097.         while (!SetTimer(hNetWnd, ID_TIMER, (1000 * timeout), NULL))
  1098.         {
  1099.             if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
  1100.                         , szAppName
  1101.                         , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
  1102.                     {
  1103.                 timo = 0;
  1104.                 return(FALSE);
  1105.             }
  1106.         }
  1107.     }
  1108.  
  1109.     return(TRUE);
  1110. }
  1111.  
  1112.  
  1113. BOOL    UDPSend(SOCKET sSocket)
  1114. {
  1115.     char    msg[3] = "\0\0\0";
  1116.  
  1117.     strcpy(msg, "\n");
  1118.     if (send(sSocket, msg, 1, 0) != 1)
  1119.         return(FALSE);
  1120.  
  1121.     return(TRUE);
  1122. }
  1123.  
  1124.  
  1125. BOOL    HandleLargeTimeout(void)
  1126. {
  1127.     if (rtt_tempto > 65)
  1128.     {
  1129.         rtt_tempto -= 65;
  1130.         timo = rtt_tempto;
  1131.         if (!rtt_register(timo))
  1132.             return(FALSE);
  1133.         else return(TRUE);
  1134.     }
  1135.     return(FALSE);
  1136. }
  1137.  
  1138.  
  1139.