home *** CD-ROM | disk | FTP | other *** search
- // Contents ---------------------------------------------------------------
- //
- // netwrkm.c -- Networking functions for NTime
- //
- // Version 1.0.1, a Windows Socket Time Client
- //
- // Copyright (C) Frederick W. Bent 1994
- // All rights reserved.
- //
- //
- // Redistribution and use in source and binary forms are permitted provided
- // that the above copyright notice and this paragraph are duplicated in all
- // such forms and that any documentation, advertising materials, and other
- // materials related to such distribution and use acknowledge that the
- // software was developed by Frederick W. Bent. In addition, if you wish
- // to distribute this program in source and/or binary forms with other
- // samples of WinSock programs, you must first contact the author so that
- // I can keep accurate records of its usage. The name of the author may
- // not be used to endorse or promote products derived from this software
- // without specific prior written permission. Specifically, do not modify
- // this source in any way and re-distribute it without the author's prior
- // consent. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OF
- // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
- // OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- //
- //
- // Description
- //
- // Module NETWRKM uses Windows Sockets asynchronous (message based)
- // calls to query a remote time server for the current time.
- // Module NTIME initiates the operation by calling FingerStart(), and
- // NETWRKM signals completion by calling TimeFinish(). NETWRKM uses
- // DSPLIST functions to send the retrieved data to the NTIME user
- // interface module.
- //
- // Ends -------------------------------------------------------------------
-
-
- // Legal Stuff --------------------------------------------------------------
- //
- // Finger Version 3.1, a Windows Sockets Time Client
- //
- // Copyright 1992, 1993 Network Research Corporation
- //
- // Permission to use, modify, and distribute this software and its
- // documentation for any purpose and without fee is hereby granted, provided
- // that the above copyright notice appears in all copies and that both
- // that copyright notice and this permission notice appear in supporting
- // documentation. NRC makes no claims as to the suitability of this software
- // for any purpose.
- //
- // Ends ---------------------------------------------------------------------
-
- // History ------------------------------------------------------------------
- //
- // Aug 17 1994 FWB Added State = STATE_RECEIVING so UDP will work
- //
- // Ends ---------------------------------------------------------------------
-
- #pragma warn -par
-
- // Interface Dependencies -------------------------------------------------
-
- #define STRICT
-
- #include <windows.h>
- #include <windowsx.h>
-
- #include <winsock.h>
- #include <stdlib.h>
- #include <memory.h>
- #include <string.h>
- #include <time.h>
- #include "dsplist.h"
- #include "ntime.h"
-
- #define ID_TIMER 1
-
- /* Network window class name */
- #define NETWINDOW "WSNTime.NetWindow"
-
- // messages for windows sockets returns
-
- #define WM_SERVICE (WM_USER + 1)
- #define WM_HOSTRESOLVED (WM_USER + 2)
- #define WM_CONNECTED (WM_USER + 3)
- #define WM_OKTORECV (WM_USER + 4)
-
-
- // Type definitions ------------------------------------------------------
-
- enum tagClientState
- {
- STATE_SERVICE
- , STATE_RESOLVE
- , STATE_CONNECTING
- , STATE_SENDING
- , STATE_RECEIVING
- , STATE_FINISHED
- , STATE_CLOSING
- , STATE_WSERROR
- };
-
- typedef enum tagClientState ClientState;
-
-
- // Function prototypes ---------------------------------------------------
-
- LRESULT CALLBACK NetWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- LRESULT DoResolveHost(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- LRESULT DoConnect(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- LRESULT DoQuery(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- LRESULT DoRetrieval(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
- LRESULT DoNetClose(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
- LRESULT DoTimer(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
- LRESULT DoNetDestroy(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
- void LoadEntBuf(IPA ipa);
-
-
- BOOL HandleLargeTimeout(void);
- void rtt_init(void);
- void rtt_newpack(void);
- int rtt_start(void);
- void rtt_stop(void);
- BOOL rtt_timeout(void);
- BOOL rtt_register(int timeout);
- BOOL UDPSend(SOCKET sSocket);
-
-
- // Global variables -------------------------------------------------------
-
- DECODEWORD netMsgs[] = // network window messages & handlers
- {
- {WM_SERVICE, DoResolveHost}
- , {WM_HOSTRESOLVED, DoConnect}
- , {WM_CONNECTED, DoQuery}
- , {WM_OKTORECV, DoRetrieval}
- , {WM_TIMER, DoTimer}
- , {WM_CLOSE, DoNetClose}
- , {WM_DESTROY, DoNetDestroy}
- };
-
-
- /* Maybe in the next release we will allow MULTIPLE connections...
- struct tagCLIENT
- {
- SOCKET sSocket;
- HANDLE hRequest;
- BOOL bTCPConnection;
- char szRemoteHost[MAXHOST+1];
- int Port;
- int timo;
- long temptime;
- ClientState State;
- };
- typedef struct tagCLIENT CLIENT;
- */
-
- char szRemoteHost[MAXHOST+1];
- SOCKET sSocket; // connects to remote server's socket
- HANDLE hRequest; // Async request handle
- int Port; // hold port for finger service
-
- char EntBuf[MAXGETHOSTSTRUCT]; // buf for service & resolve returns
- HWND hNetWnd; // network window handle
- HWND hMainWnd;
- time_t addminutes;
- int timo;
- int nTCPTimeOutValue;
- int nUDPTimeOutValue;
- int nUDPNumberRetry;
- unsigned long temptime;
-
- ClientState State;
-
- //
- // InitNetApp -- registers window class for the network module's invisible
- // child window. This is called only for the first instance of finger.
- //
- VOID InitNetApp(VOID)
- {
- WNDCLASS wndclass;
-
- wndclass.style = 0;
- wndclass.lpfnWndProc = NetWndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInst;
- wndclass.hIcon = 0;
- wndclass.hCursor = 0;
- wndclass.hbrBackground = 0;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = NETWINDOW;
-
- RegisterClass(&wndclass);
- }
-
- //
- // InitNetInst -- initializes the network module by creating an invisible
- // child of the main finger window which will be used to receive Windows
- // Sockets notification messages. The window will be automatically
- // destroyed when the main window exits, so no finalization is required.
- //
- BOOL InitNetInst(HWND hWnd, int nTCPTimeOut, int nUDPTimeOut, int nUDPRetry)
- {
- hMainWnd = hWnd;
- nTCPTimeOutValue = ( nTCPTimeOut > 65 ) ? 65 : nTCPTimeOut;
- nUDPTimeOutValue = nUDPTimeOut;
- nUDPNumberRetry = nUDPRetry;
-
- timo = 0;
- temptime = 0L;
-
- sSocket = INVALID_SOCKET;
- hRequest = 0;
-
- hNetWnd = CreateWindow( NETWINDOW, NULL
- , WS_CHILD
- , CW_USEDEFAULT, CW_USEDEFAULT
- , CW_USEDEFAULT, CW_USEDEFAULT
- , hWnd
- , NULL
- , hInst
- , NULL);
-
- if (hNetWnd == NULL) return(FALSE);
-
- return(TRUE);
- }
-
-
-
- /* Notes:
- * The time is the number of seconds since 00:00 (midnight) 1 January 1900
- * GMT, such that the time 1 is 12:00:01 am on 1 January 1900 GMT; this
- * base will serve until the year 2036.
- *
- * For example:
- *
- * 2,208,988,800L corresponds to 00:00 1 Jan 1970 GMT, start of UNIX time
- *
- */
-
- #define BASE_TIME 2208988800L
-
- void UpdateTime( unsigned long newtime )
- {
- struct tm *tmClock;
- time_t tClock;
- time_t tOldTime;
- char szTemp[256];
- HDC hdc;
-
-
- /* If we actually did get a response from the remote host */
- if ( newtime != 0 )
- {
- /*
- * Borland C++ 3.1 funtion which will read the
- * TZ=EST5EDT environment variable
- */
- tzset();
-
-
- tClock = newtime - BASE_TIME + addminutes; /* now in UNIX format */
- if (bUpdateSystemTime) stime(&tClock);
- else tClock -= addminutes;
- tOldTime = time(NULL);
-
- tmClock = localtime(&tClock);
- if ( !strftime(szTemp, sizeof(szTemp), "%a %b %d %H:%M:%S %Y %Z", tmClock))
- {
- /* remove the newline character from the string */
- lstrcpy((LPSTR) szTemp, (LPSTR)asctime(tmClock));
- szTemp[lstrlen((LPSTR)szTemp)-1] = '\0';
- }
-
- hdc = GetDC(hMainWnd);
- if (bUpdateSystemTime)
- {
-
- WinPrintf( hdc, -1, 0, "System time set to %s", (LPSTR) szTemp );
- } else
- WinPrintf( hdc, -1, 0, "Time from host using %s/IP = %s"
- , (LPSTR) (bShouldUseTCP ? "TCP" : "UDP" )
- , (LPSTR) szTemp );
- WinPrintf( hdc, -1, 0, "The difference is %0ld seconds", (long)(tOldTime - tClock) );
- ReleaseDC(hMainWnd, hdc);
- } else {
- LoadString(hInst, FE_INVLDTIME, (LPSTR)szTemp, sizeof(szTemp));
-
- MessageBeep(MB_ICONEXCLAMATION);
- MessageBox(hMainWnd, (LPSTR) szTemp, szAppName,
- MB_ICONEXCLAMATION | MB_OK );
-
- hdc = GetDC(hMainWnd);
- WinPrintf( hdc, -1, 0, szTemp );
- ReleaseDC(hMainWnd, hdc);
- }
- }
-
-
- void CancelRequest(HANDLE hRequest)
- {
- int err;
-
- if (hRequest == 0) return;
-
- err = WSACancelAsyncRequest(hRequest);
- hRequest = 0;
-
- if (err == SOCKET_ERROR)
- {
- err = WSAGetLastError();
- if ((err == WSAEALREADY) || (err == WSAEINVAL)) return;
- ReportFingerErr(FE_CANCEL, err);
- }
- return;
- }
-
-
- void NetClose(void)
- {
- SendMessage(hNetWnd, WM_CLOSE, 0, 0L);
- }
-
-
- void CloseTheSocket(SOCKET sSock)
- {
- int err;
- char szInputBuffer[80];
- int iInputSize;
-
- if (sSock == INVALID_SOCKET) return;
-
- /* Perform a graceful termination */
- err = shutdown(sSock, 1); // no sending now
-
- if ( err == SOCKET_ERROR ) {
- ReportFingerErr(FE_SHUTDWN, WSAGetLastError());
- }
-
- State = STATE_CLOSING;
-
- /* Get all remaining data, if any... */
-
- iInputSize = sizeof(szInputBuffer);
- while( (err = recv(sSock, (void FAR *)szInputBuffer, iInputSize, 0)) != 0 )
- {
- if (err == SOCKET_ERROR)
- {
- err = WSAGetLastError();
- if ( err != WSAEWOULDBLOCK )
- {
- ReportFingerErr(FE_SHUTDWN, err);
- }
- break;
- }
- }
-
- /* turn off all messages, its now a blocking socket */
- err = WSAAsyncSelect(sSock, hNetWnd, 0, 0);
-
- /* now close the socket, will also flush send buffers */
-
- closesocket(sSock);
- sSocket = INVALID_SOCKET;
- }
-
-
- //
- // NetWndProc -- callback function for network window. The network window
- // is a child window created especially to receive windows sockets network
- // messages. The function decodes and routes to appropriate message handler.
- //
- LRESULT CALLBACK NetWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- int i;
-
- for (i = 0; i < dim(netMsgs); i++)
- {
- if (wMsg == netMsgs[i].Code)
- return((*netMsgs[i].Fxn)(hWnd, wMsg, wParam, lParam));
- }
-
- return(DefWindowProc(hWnd, wMsg, wParam, lParam));
- }
-
-
- //
- // FingerStart -- called by FINGER module to initiate a conversation with
- // the remote finger server. We start by resolving the finger tcp service
- // to a port number. Windows Sockets WSAAsync routines signal completion
- // by posting messages, which are dispatched to appropriate handlers.
- //
- VOID FingerStart(PSTR szHost)
- {
-
- HDC hdc;
-
- if (strlen(szUser) > 0 )
- addminutes = atol( szUser ); // * 60L;
- else
- addminutes = 0L;
-
- timo = nTCPTimeOutValue;
- State = STATE_CONNECTING;
-
- strcpy(szRemoteHost, szHost);
-
- if (timo > 0)
- {
- /* Generate a WM_TIMER every nTCPTimeOutValue seconds */
- while (!SetTimer(hNetWnd, ID_TIMER, (1000 * timo), NULL))
- {
- if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
- , szAppName
- , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- TimeFinish(FE_ERROR);
- return;
- }
- }
- }
-
- OpenDisplayList(); // new display list will contain received data
-
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, 1, 0, "Resolving %s...", (LPSTR)szRemoteHost );
- ReleaseDC( hMainWnd, hdc );
-
- State = STATE_SERVICE;
-
- if ((hRequest = WSAAsyncGetServByName(hNetWnd, WM_SERVICE
- , "time", (bShouldUseTCP ? "tcp" : "udp")
- , EntBuf, sizeof(EntBuf))) == 0)
- {
- ReportFingerErr(FE_NOPORT, WSAGetLastError());
- // TimeFinish(FE_ERROR);
- ((SERVENT *) EntBuf)->s_port = htons(IPPORT_TIMESERVER);
- }
- }
-
-
- VOID FingerStop(VOID)
- {
- if (timo != 0 )
- {
- timo = 0;
- KillTimer(hNetWnd,ID_TIMER);
- }
-
- if (hRequest != 0) CancelRequest(hRequest);
- if (sSocket != INVALID_SOCKET) CloseTheSocket(sSocket);
- }
-
-
- LRESULT DoNetClose(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- KillTimer(hWnd, ID_TIMER);
- CancelRequest(hRequest);
- CloseTheSocket(sSocket);
- return(FALSE);
- }
-
-
- LRESULT DoNetDestroy(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- PostQuitMessage(0);
- return(FALSE);
- }
-
-
- /*
- * If a UDP connection, then see if we should retransmit...
- *
- * For some reason, the Trumpet WinSock rev B6, or rev B10
- * will not indicate a timeout when using a non-blocking
- * STREAM socket, so this is needed to fake a timeout for
- * a TCP connection as well.
- */
- LRESULT DoTimer(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
-
- KillTimer(hWnd, ID_TIMER);
- timo = 0;
-
- switch(State)
- {
- #ifdef RECOVER_TIMEOUT
- default:
- if (IDRETRY == MessageBox(hMainWnd, "Timeout occurred attempting connection!", szAppName, MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- timo = nTCPTimeOutValue;
- while (!SetTimer(hWnd, ID_TIMER, (1000 * timo), NULL))
- {
- if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
- , szAppName
- , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- timo = 0;
- CancelRequest(hRequest);
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "Request canceled.");
- ReleaseDC( hMainWnd, hdc );
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
- }
- } else {
- CancelRequest(hRequest);
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "Request canceled." );
- ReleaseDC( hMainWnd, hdc );
- TimeFinish(FE_ERROR);
- }
- break;
- #else
- case STATE_SERVICE:
- PostMessage(hWnd, WM_SERVICE, (WPARAM) hRequest, WSAMAKEASYNCREPLY(sizeof(SERVENT),WSAETIMEDOUT));
- break;
-
- case STATE_RESOLVE:
- PostMessage(hWnd, WM_HOSTRESOLVED, (WPARAM) hRequest, WSAMAKEASYNCREPLY(sizeof(HOSTENT),WSAETIMEDOUT));
- break;
-
- case STATE_CONNECTING:
- PostMessage(hWnd, WM_CONNECTED, (WPARAM) sSocket, WSAMAKESELECTREPLY(FD_CONNECT,WSAETIMEDOUT));
- break;
- #endif
-
- case STATE_SENDING:
- if (HandleLargeTimeout())
- return(FALSE);
-
- /* UDP Timeout yet? */
- if (!rtt_timeout())
- {
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "re-sending UDP datagram" );
- ReleaseDC( hMainWnd, hdc );
-
- /* Resend the packet */
- if (!UDPSend(sSocket))
- {
- ReportFingerErr(FE_NOSEND, WSAGetLastError());
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- timo = rtt_start();
- if (!rtt_register(timo))
- {
- CancelRequest(hRequest);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- } else {
- #ifdef RECOVER_TIMEOUT
- if (IDRETRY == MessageBox(hMainWnd, "Timeout occurred waiting for response!", szAppName, MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- rtt_init();
- rtt_newpack();
- if (!UDPSend(sSocket))
- {
- ReportFingerErr(FE_NOSEND, WSAGetLastError());
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- timo = rtt_start();
- if (timo > 65) timo = 65;
- while (!SetTimer(hWnd, ID_TIMER, (1000 * timo), NULL))
- {
- if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
- , szAppName
- , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- timo = 0;
- CancelRequest(hRequest);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
- }
- } else {
- CancelRequest(hRequest);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
- #else
- PostMessage(hWnd, WM_CONNECTED, sSocket, WSAMAKESELECTREPLY(FD_CONNECT,WSAETIMEDOUT));
- #endif
- }
- break;
- }
-
- return(FALSE);
- }
-
-
- //
- // DoResolveHost -- resolves host specifier to an IP address. Since we
- // allow a "dotted decimal" IP address to be entered in lieu of a DNS host
- // name, we check for this syntax before assuming a DNS name.
- //
- LRESULT DoResolveHost(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- IPA ipa;
- int err;
-
-
- /* Is this the response to OUR request? */
-
- if ( (HANDLE)wParam != hRequest ) return(FALSE);
-
- if ((err = WSAGETASYNCERROR(lParam)) != 0)
- {
- ReportFingerErr(FE_NOPORT, err); // cannot locate finger service
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- Port = ntohs(((SERVENT *)EntBuf)->s_port); // we're going to reuse the buffer
-
- // if host specifier is dotted decimal ip address, resolve right here
- if ((ipa = INET_ADDR(szRemoteHost)) != INADDR_NONE)
- {
- LoadEntBuf(ipa);
- PostMessage(hNetWnd, WM_HOSTRESOLVED, (WPARAM)hRequest, 0L);
- return(FALSE);
- }
-
- State = STATE_RESOLVE;
-
- // assume specifier is DNS host name
- if ((hRequest = WSAAsyncGetHostByName(hNetWnd, WM_HOSTRESOLVED, szRemoteHost, EntBuf, sizeof(EntBuf))) == 0)
- {
- ReportFingerErr(FE_NOHOST, WSAGetLastError());
- TimeFinish(FE_ERROR);
- }
-
- return(FALSE);
- }
-
- //
- // LoadEntBuf -- loads the EntBuf (sufficiently) with a HOSTENT and
- // referenced IPA. This is so we can return IPAs in the same
- // manner as a WSAAsync call.
- //
- void LoadEntBuf(IPA ipa)
- {
- LPHOSTENT phe = (LPHOSTENT) EntBuf;
- LPPIPA ppipa = (LPPIPA) (EntBuf + sizeof(HOSTENT));
- LPIPA pipa = (LPIPA) (EntBuf + sizeof(HOSTENT) + sizeof(LPPIPA));
-
- _fmemset(phe, 0, sizeof(HOSTENT));
- phe->h_addr_list = (char FAR * FAR *) ppipa;
- *ppipa = pipa;
- *pipa = ipa;
- }
-
-
- //
- // DoConnect -- Responds to the WM_HOSTRESOLVED message by allocating
- // a socket and trying to connect to remote time server.
- //
- LRESULT DoConnect(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- int err;
-
-
- /* Is this for us? */
- if ( (HANDLE)wParam != hRequest ) return(FALSE);
-
- if ((err = WSAGETASYNCERROR(lParam)) != 0)
- {
- ReportFingerErr(FE_NOHOST, err); // could not resolve host name
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- hRequest = 0;
-
- if ((sSocket = socket(AF_INET, (bShouldUseTCP ? SOCK_STREAM : SOCK_DGRAM), 0)) != INVALID_SOCKET )
- {
- SOCKADDR_IN server;
- SOCKADDR_IN client;
- HOSTENT *phe = (HOSTENT *) EntBuf;
- BOOL bDebug;
-
- bDebug=TRUE;
- setsockopt(sSocket,
- SOL_SOCKET, SO_DEBUG, (char FAR *)&bDebug,
- sizeof(bDebug));
-
- /*
- * Bind the connectionless socket to any port on the client
- */
- if (!bShouldUseTCP)
- {
- memset(&client, 0, sizeof(client));
- client.sin_family = AF_INET;
- client.sin_port = htons(0);
- client.sin_addr.s_addr = htonl(INADDR_ANY);
- if ( bind(sSocket, (LPSOCKADDR)&client, sizeof(client)) == SOCKET_ERROR )
- {
- err = WSAGetLastError();
- ReportFingerErr(FE_NOBIND, err);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
- }
-
- memset(&server, 0, sizeof(server));
- server.sin_family = AF_INET;
- server.sin_port = htons(Port);
- server.sin_addr = *((IN_ADDR FAR *) *phe->h_addr_list);
-
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "Trying %s...", (LPSTR)szRemoteHost );
- ReleaseDC( hMainWnd, hdc );
-
- State = STATE_CONNECTING;
-
- // post message when connect is established
- if ( WSAAsyncSelect(sSocket, hNetWnd, WM_CONNECTED, FD_CONNECT) == SOCKET_ERROR )
- {
- err = WSAGetLastError();
- ReportWSError(err);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- if (connect(sSocket, (SOCKADDR *)&server, sizeof(server)) == SOCKET_ERROR)
- {
- if ((err = WSAGetLastError()) == WSAEWOULDBLOCK)
- {
- if ( WSAAsyncSelect(sSocket, hNetWnd, WM_CONNECTED, FD_CONNECT) == SOCKET_ERROR )
- {
- err = WSAGetLastError();
- ReportWSError(err);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- } else {
- State = STATE_WSERROR;
- closesocket(sSocket); // Not connected, so no need to try later...
- sSocket = INVALID_SOCKET;
- ReportFingerErr(FE_NOCONN, err);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
- }
-
- /*
- * There is no UDP "connection" so we must fake it...
- */
- if (!bShouldUseTCP)
- PostMessage(hNetWnd, WM_CONNECTED, (WPARAM)sSocket, (LPARAM)WSAMAKESELECTREPLY(FD_CONNECT,0));
-
- }
- else
- {
- State = STATE_WSERROR;
- ReportFingerErr(FE_NOSOCK, WSAGetLastError());
- TimeFinish(FE_ERROR);
- }
-
- return(FALSE);
- }
-
- //
- // DoQuery -- Responds to the FD_CONNECT event by enabling FD_READ
- // and FD_CLOSE events
- //
- LRESULT DoQuery(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- int err;
-
-
- if (State != STATE_CONNECTING) return(FALSE);
-
- if ((err = WSAGETSELECTERROR(lParam)) != 0)
- {
- State = STATE_WSERROR;
- ReportFingerErr(FE_NOCONN, err); // could not connect to server
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- if ((err = WSAGETSELECTEVENT(lParam)) != FD_CONNECT)
- {
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "Huh... Expected a FD_CONNECT (%d)", err );
- ReleaseDC( hMainWnd, hdc );
- }
-
- if ((SOCKET)wParam != sSocket)
- {
- ReportFingerErr(IDS_BRK_WINSOCK, WSABASEERR);
- // TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- // post message when data is available for read
- if (WSAAsyncSelect(sSocket, hNetWnd, WM_OKTORECV, FD_READ | FD_CLOSE) == SOCKET_ERROR)
- {
- State = STATE_WSERROR;
- err = WSAGetLastError();
- ReportWSError(err);
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- // Send empty message if UPD
- if (!bShouldUseTCP)
- {
- State = STATE_SENDING;
-
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "sending UDP datagram" );
- ReleaseDC( hMainWnd, hdc );
-
- KillTimer(hWnd, ID_TIMER);
- rtt_init();
- rtt_newpack();
-
- if (!UDPSend(sSocket))
- {
- ReportFingerErr(FE_NOSEND, WSAGetLastError());
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- /*
- * Start out timeout waiting for response
- */
- timo = rtt_start();
- if (!rtt_register(timo))
- {
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
- } else {
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "[%s]", (LPSTR)szRemoteHost );
- ReleaseDC( hMainWnd, hdc );
-
- State = STATE_RECEIVING;
- }
-
- return(FALSE);
- }
-
-
- #define TVAL_SIZE 4
-
- // Network function
-
- LRESULT DoRetrieval(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
-
- // Summary ----------------------------------------------------------------
- //
- // Handle the FD_READ and FD_CLOSE events.
- //
- // Parameters
- //
- // hWnd Handle of the window.
- //
- // Msg Message.
- //
- // wParam First message paramter.
- //
- // lParam Second message parameter.
- //
- //
- // Returns
- //
- // LRESULT
- //
- // Returns FALSE of the dialog message was handled, otherwise TRUE.
- //
- // Ends -------------------------------------------------------------------
-
- {
- unsigned long buf;
- int nchars;
- int err;
-
-
-
- if ((err = WSAGETSELECTERROR(lParam)) != 0)
- {
- ReportFingerErr(FE_NOCONN, err); // could not connect to server
- TimeFinish(FE_ERROR);
- return(FALSE);
- }
-
-
- /* If not for our socket, ignore it... */
- if ((SOCKET)wParam != sSocket)
- return(FALSE);
-
-
- /* receives data not to exceed buf size & reenables notification
- of more data pending FD_READ */
-
- switch(WSAGETSELECTEVENT(lParam))
- {
- case FD_CLOSE:
-
- /* We have gotten the data, so stop the timer */
-
- if ( timo != 0 )
- {
- timo = 0;
- KillTimer(hWnd, ID_TIMER);
- }
-
- if ( State != STATE_CLOSING )
- {
- CloseTheSocket(sSocket);
-
- UpdateTime( temptime ); // Handle the time that we got
-
- CloseDisplayList(); // close list if error or end-of-data
-
- TimeFinish(0); // signal end-of-finger
- }
- break;
-
- case FD_READ:
- err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_CLOSE);
- if ( err == SOCKET_ERROR )
- {
- State = STATE_WSERROR;
- err = WSAGetLastError();
- ReportWSError(err);
- return(FALSE);
- }
-
- nchars = recv(sSocket, (char FAR *) &buf, TVAL_SIZE, 0);
- if ( nchars == SOCKET_ERROR )
- {
- /*
- * If this would block, then try again
- */
- temptime = 0L;
- err = WSAGetLastError();
- if ( err == WSAEWOULDBLOCK )
- {
- err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_READ | FD_CLOSE);
- if ( err == SOCKET_ERROR )
- {
- State = STATE_WSERROR;
- err = WSAGetLastError();
- CloseTheSocket(sSocket);
- ReportWSError(err);
- }
- return(FALSE);
- } else {
- State = STATE_WSERROR;
- CloseTheSocket(sSocket);
- ReportFingerErr(FE_NORECV, err);
- }
- } else {
- if ( ( State == STATE_RECEIVING ) || ( State == STATE_SENDING ) )
- {
- State = STATE_FINISHED;
-
- if ( nchars == TVAL_SIZE )
- {
- temptime = ntohl( buf );
- } else { // 0 bytes read - service not available
- temptime = 0L;
- }
- }
- }
-
- err = WSAAsyncSelect(sSocket, hWnd, wMsg, FD_READ | FD_CLOSE);
- if ( err == SOCKET_ERROR )
- {
- State = STATE_WSERROR;
- err = WSAGetLastError();
- ReportWSError(err);
- return(FALSE);
- }
-
- if (!bShouldUseTCP)
- {
- rtt_stop();
- }
-
- /* Fake a closure event */
- PostMessage(hNetWnd, WM_OKTORECV, (WPARAM)sSocket, (LPARAM)WSAMAKESELECTREPLY(FD_CLOSE,0));
-
-
- break;
- default:
- {
- HDC hdc;
-
- err = WSAGETSELECTEVENT(lParam);
- hdc = GetDC( hMainWnd );
- WinPrintf( hdc, -1, 0, "Huh... Expected a FD_CONNECT | FD_CLOSE (%d)", err );
- ReleaseDC( hMainWnd, hdc );
- }
- break;
-
- }
-
- return(FALSE);
- }
-
-
- #define RTT_RXTMIN 2
- #define RTT_RXTSTRT 3
- #define RTT_RXTMAX (nUDPTimeOutValue) // 120
- #define RTT_MAXNREXMT 4
- int exp_backoff[ RTT_MAXNREXMT + 1 ] =
- { 1, 2, 4, 8, 16 };
- // 0 1 2 3 4
- // [0] == 3sec not used
- // [1] == 6sec second retransmission
- // [2] == 24sec third retransmission
- // [3] == 192sec fourth retransmission
- // [4] == 3072sec fifth retransmission
- //
- // RTT_RXTMAX is the highest value that will be used for any
- // single retransmission attempt.
- //
- // nUDPNumberRetry will limit the number of retry attempts.
-
- int rtt_currto;
- int rtt_nrexmt;
- int rtt_tempto;
- int rtt_totto;
-
- void rtt_init(void)
- {
- rtt_currto = 0;
- rtt_tempto = 0;
- }
-
-
- void rtt_newpack(void)
- {
- rtt_nrexmt = 0;
- rtt_totto = 0;
- }
-
-
- int rtt_start(void)
- {
- if ( rtt_nrexmt > 0 )
- {
- rtt_currto *= exp_backoff[rtt_nrexmt];
- if ( rtt_currto > RTT_RXTMAX )
- {
- rtt_currto = RTT_RXTMAX;
- rtt_nrexmt = RTT_MAXNREXMT; // OK, do not try again...
- }
- rtt_tempto = rtt_currto;
- return(rtt_currto);
- }
-
- rtt_currto = RTT_RXTSTRT; // first timeout at RTT_RXTSTRT sec.
- return (rtt_currto);
- }
-
-
- void rtt_stop(void)
- {
- }
-
-
- BOOL rtt_timeout(void)
- {
- rtt_stop();
- if (++rtt_nrexmt > RTT_MAXNREXMT)
- return(TRUE);
- return(FALSE);
- }
-
-
- BOOL rtt_register(int timeout)
- {
- if (timeout > 65) timeout = 65;
- if (timeout > 0)
- {
- while (!SetTimer(hNetWnd, ID_TIMER, (1000 * timeout), NULL))
- {
- if (IDCANCEL == MessageBox(hMainWnd, "Unable to register watchdog timer!"
- , szAppName
- , MB_ICONEXCLAMATION | MB_RETRYCANCEL))
- {
- timo = 0;
- return(FALSE);
- }
- }
- }
-
- return(TRUE);
- }
-
-
- BOOL UDPSend(SOCKET sSocket)
- {
- char msg[3] = "\0\0\0";
-
- strcpy(msg, "\n");
- if (send(sSocket, msg, 1, 0) != 1)
- return(FALSE);
-
- return(TRUE);
- }
-
-
- BOOL HandleLargeTimeout(void)
- {
- if (rtt_tempto > 65)
- {
- rtt_tempto -= 65;
- timo = rtt_tempto;
- if (!rtt_register(timo))
- return(FALSE);
- else return(TRUE);
- }
- return(FALSE);
- }
-
-
-