home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / winsock / fingd100 / src / net.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  14.1 KB  |  577 lines

  1. // Contents ---------------------------------------------------------------
  2. //
  3. //   net.c -- WinSock related functions
  4. //
  5. //   Version 1.0, a Windows Socket Finger Daemon
  6. //
  7. //   Copyright (C) Frederick W. Bent 1994
  8. //   All rights reserved.
  9. //
  10. //
  11. // Description
  12. //
  13. //    This file contains the networking portion of the server.  The
  14. //    server gets a socket and binds it to the finger port.  listen()
  15. //    is used to accept the connections from the clients.
  16. //
  17. //    WSAAsyncSelect() is used to cause an FD_ACCEPT to be sent to the
  18. //    network window.  WSAAsyncSelect() is used to modify the
  19. //    accepted socket so that FD_READ, FD_WRITE and FD_CLOSE messages
  20. //    as used to notify the server about the various states of the
  21. //    client socket.
  22. //
  23. // Ends -------------------------------------------------------------------
  24.  
  25. // History ----------------------------------------------------------------
  26. //
  27. // 6/28/94  1.0  Fred Bent         Started implementation
  28. //
  29. // Ends -------------------------------------------------------------------
  30.  
  31. // Interface Dependencies -------------------------------------------------
  32.  
  33. #define STRICT
  34.  
  35. #include <windows.h>
  36. #include <windowsx.h>
  37. #include <winsock.h>
  38. #include <time.h>
  39. #include <wassert.h>
  40. #include "fingerd.h"
  41.  
  42. #define MAXHOSTNAMELEN    64
  43.  
  44. // End Interface Dependencies ---------------------------------------------
  45.  
  46. // External Declarations -------------------------------------------------
  47.  
  48. extern    HWND    hwndMain;      // handle of main window
  49. extern    HINSTANCE    hInst;         // our main instance
  50. extern    char szMainBuffer[SENDBUFLEN];    // transfer buffer holds in/outbound text
  51. extern LPCLIENT fingerClientsHead;    // linked list root
  52.  
  53. // End External Declarations ----------------------------------------------
  54.  
  55. // Server Implementation --------------------------------------------------
  56.  
  57.     SOCKET      sListen;       // awaits connection requests
  58.     HWND    hwndNetwork;   // our invisible network "window"
  59.     char    szNetworkClass[CLASS_SIZE];    // class name of network window
  60.     char    szLocalHostName[MAXHOSTNAMELEN];
  61.  
  62.  
  63. // WindowProc Function
  64.  
  65.     LRESULT CALLBACK NetWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
  66.  
  67. // Summary ----------------------------------------------------------------
  68. //
  69. //    The network window procedure.  It is used to handle the
  70. //    SOCKET_MESSAGE posted due to network activity.  This allows the
  71. //    daemon to be asynchronous.
  72. //
  73. // Parameters
  74. //
  75. //    hWnd    Handle of the window.
  76. //
  77. //    Msg    Message.
  78. //
  79. //    wParam    First message paramter.
  80. //
  81. //    lParam    Second message parameter.
  82. //
  83. // Returns
  84. //
  85. //    BOOL    Returns FALSE when the message has been processed, otherwise
  86. //        returns the result of DefWindowProc().
  87. //
  88. // Ends -------------------------------------------------------------------
  89.  
  90.     {
  91.        LPCLIENT     lpClient;
  92.        SOCKET    sSocket;
  93.        SOCKADDR_IN    saPeer;
  94.        int        iAddrSize;
  95.        int        iError;
  96.  
  97.        lpClient = NULL;
  98.  
  99.        switch (Msg)
  100.        {
  101.          case SOCKET_MESSAGE:
  102.          {
  103.         switch(WSAGETSELECTEVENT(lParam))
  104.         {
  105.             case FD_ACCEPT:
  106.             {
  107.             LPSOCKADDR_IN    lpsaHostAddr;
  108.                         LPHOSTENT    lpheHostEnt;
  109.  
  110.             /* Get a pending accept */
  111.  
  112.             iAddrSize = sizeof(SOCKADDR_IN);
  113.             sSocket = accept( sListen, (LPSOCKADDR) &saPeer, (LPINT) &iAddrSize );
  114.             if ( sSocket == INVALID_SOCKET )
  115.             {    DisplayWSError("Couldn't accept() connection.");
  116.                 return(FALSE);
  117.             }
  118.  
  119.             /* Allocate socket specific data */
  120.  
  121.             lpClient = fingerAddClient(sSocket);
  122.             if ( lpClient == NULL ) return(FALSE);
  123.  
  124.             /* Remember the connected Peer's address */
  125.  
  126.             lpClient->saPeer = saPeer;
  127.  
  128.                         /* Get a far pointer to it...*/
  129.             lpsaHostAddr = (LPSOCKADDR_IN) &(lpClient->saPeer);
  130.  
  131.             lpheHostEnt = gethostbyaddr((LPSTR)&(lpsaHostAddr->sin_addr.s_addr), 4, PF_INET);
  132.             if ( lpheHostEnt == NULL )
  133.             {
  134.                 /* OK, cannot find a hostname, so use the dot notation */
  135.                 lstrcpy((LPSTR)lpClient->szPeer, inet_ntoa(lpsaHostAddr->sin_addr));
  136.             } else {
  137.                 lstrcpy((LPSTR)lpClient->szPeer, (LPSTR)(lpheHostEnt->h_name));
  138.             }
  139.  
  140.             /* OK now get messages from this socket */
  141.  
  142.             if ( WSAAsyncSelect( sSocket, hwndNetwork
  143.                        , SOCKET_MESSAGE
  144.                        , (FD_READ | FD_CLOSE)) == SOCKET_ERROR)
  145.             {
  146.                 DisplayWSError("Couldn't select() on client socket.");
  147.                 fingerDestroyClient(lpClient);
  148.                 return(FALSE);
  149.             }
  150.  
  151.             fingerLog(DEBUG_HIGH | LOG_TIME, IDS_CONNECT_S, (LPSTR) lpClient->szPeer, sSocket);
  152.  
  153.             return(FALSE);
  154.             } // FD_ACCEPT
  155.  
  156.  
  157.             case FD_READ:    // WinSock has something for us
  158.             {
  159.             int iError;
  160.  
  161.             /* Find the corresponding client */
  162.  
  163.             lpClient = fingerSocketToClient((SOCKET) wParam);
  164.             if (lpClient == NULL) return(FALSE);
  165.  
  166. #ifdef    WINSOCK_BUG
  167.             if ( netSelectEvents(lpClient, (FD_WRITE | FD_CLOSE)) )
  168.                 return (FALSE);
  169. #endif
  170.  
  171.             /* Attempt to get the data from this client */
  172.  
  173.             if ( fingerServer(lpClient) )
  174.             {
  175.                 if ( lpClient->iState == STATE_WSERROR )
  176.                                 {
  177.                     WSASetLastError(lpClient->iExtErr);
  178.                     DisplayWSError("");
  179.                 }
  180.                 fingerDestroyClient(lpClient);
  181.                 return(FALSE);
  182.             }
  183.  
  184. #ifdef    WINSOCK_BUG
  185.             if ( netSelectEvents(lpClient, (FD_READ | FD_WRITE | FD_CLOSE)) )
  186.             {
  187.                 DisplayWSError("");
  188.                 fingerDestroyClient(lpClient);
  189.             }
  190. #endif
  191.  
  192.             return(FALSE);
  193.             } // FD_READ
  194.  
  195.  
  196.             case FD_WRITE:    // WinSock ready to send data on this socket
  197.             {
  198.             lpClient = fingerSocketToClient((SOCKET) wParam);
  199.             if (lpClient == NULL) return(FALSE);
  200.  
  201. #ifdef    WINSOCK_BUG
  202.             if ( netSelectEvents(lpClient, (FD_READ | FD_CLOSE)))
  203.             {
  204.                 DisplayWSError("");
  205.                 fingerDestroyClient(lpClient);
  206.                 return(FALSE);
  207.             }
  208. #endif
  209.  
  210.             if ( !fingerSendFile(lpClient) )
  211.             {
  212.                 fingerDestroyClient(lpClient);
  213.                 return(FALSE);
  214.             }
  215. #ifdef    WINSOCK_BUG
  216.             if ( netSelectEvents(lpClient, (FD_READ | FD_WRITE | FD_CLOSE)))
  217.             {
  218.                 DisplayWSError("");
  219.                 fingerDestroyClient(lpClient);
  220.             }
  221. #endif
  222.  
  223.             return(FALSE);
  224.             } // FD_WRITE
  225.  
  226.  
  227.             case FD_CLOSE:    // Hey, it closed on us...
  228.             {
  229.             lpClient = fingerSocketToClient((SOCKET) wParam);
  230.             if (lpClient == NULL) return(FALSE);
  231.  
  232.             fingerDestroyClient(lpClient);
  233.             return(FALSE);
  234.             } // FD_CLOSE
  235.  
  236.             default:    // Should never get here!!!
  237.             break;
  238.         }
  239.          } // SOCKET_MESSAGE
  240.  
  241.          case WM_CLOSE:    // Network window being closed...
  242.          {
  243.         fingerDestroyClient(fingerClientsHead);
  244.         fingerClientsHead = NULL;
  245.         WSACleanup();
  246.         return(FALSE);
  247.          } // WM_CLOSE
  248.        }
  249.  
  250.        return(DefWindowProc(hWnd,Msg,wParam,lParam));
  251.     }
  252.  
  253.  
  254. // Function
  255.  
  256.     BOOL netInit(void)
  257.  
  258. // Summary ----------------------------------------------------------------
  259. //
  260. //    Creates the network windows, which is a child of hwndMain.  The
  261. //    main socket that listens for client connections (sListen) is also
  262. //    created.  This socket will affect the clients that are accept().
  263. //
  264. // Parameters
  265. //
  266. //    none
  267. //
  268. // Return
  269. //
  270. //    BOOL    Returns FALSE if error
  271. //
  272. // Ends -------------------------------------------------------------------
  273.  
  274.     {
  275.        WNDCLASS    wndclass;
  276.        SOCKADDR_IN     sin;
  277.        LPSERVENT     lpseServEnt;
  278.        LPHOSTENT    lpheHostEnt;
  279.        BOOL        bDebug;
  280.            int        iSndSize;
  281.  
  282.  
  283.        /* Get the local host name and save it */
  284.        if (gethostname((LPSTR)szLocalHostName, sizeof(szLocalHostName)) == SOCKET_ERROR)
  285.        {
  286.         lstrcpy((LPSTR) szLocalHostName, (LPSTR) STRING_UNKNOWN);
  287.        } else {
  288.         lpheHostEnt = gethostbyname((LPSTR)szLocalHostName);
  289.         if (lpheHostEnt != NULL)
  290.         {
  291.                     lstrcpy((LPSTR) szLocalHostName, lpheHostEnt->h_name);
  292.                 }
  293.            }
  294.        /*
  295.         * Setup the invisible network window which will get the
  296.         * WinSock messages
  297.         */
  298.  
  299.        wndclass.style = 0;
  300.        wndclass.lpfnWndProc = NetWndProc;
  301.        wndclass.cbClsExtra = 0;
  302.        wndclass.cbWndExtra = 0;
  303.        wndclass.hInstance = hInst;    // Owned
  304.        wndclass.hIcon = NULL;
  305.        wndclass.hCursor = NULL;
  306.        wndclass.hbrBackground = NULL;
  307.        wndclass.lpszMenuName = NULL;
  308.        wndclass.lpszClassName = szNetworkClass;
  309.  
  310.        if (!RegisterClass(&wndclass)) return(TRUE);
  311.  
  312.        hwndNetwork = CreateWindow( (LPSTR)szNetworkClass, NULL
  313.                 , WS_CHILD
  314.                 , CW_USEDEFAULT, CW_USEDEFAULT
  315.                 , CW_USEDEFAULT, CW_USEDEFAULT
  316.                 , hwndMain
  317.                 , NULL
  318.                 , hInst
  319.                 , NULL);
  320.  
  321.        if (hwndNetwork == NULL)
  322.        {
  323.         UnregisterClass((LPSTR)szNetworkClass, hInst);
  324.         return(TRUE);
  325.        }
  326.  
  327.  
  328.        /* Make a stream-socket */
  329.        sListen = socket(AF_INET, SOCK_STREAM, 0);
  330.        if( sListen == INVALID_SOCKET )
  331.        {
  332.           DisplayWSError("Couldn't make socket.");
  333.           return(TRUE);
  334.        }
  335.  
  336.        /* Attempt to find an entry for "finger", "tcp" */
  337.        lpseServEnt = getservbyname((LPSTR)FINGER_NAME, NULL);
  338.        if (lpseServEnt == NULL)
  339.        {
  340.         /* Couldn't find one, so use hard coded value... */
  341.         DisplayWSError("Couldn't resolve FINGER service port.");
  342.         sin.sin_port = htons(FINGER_PORT);
  343.        } else {
  344.         sin.sin_port = lpseServEnt->s_port;
  345.        }
  346.  
  347.        sin.sin_family = AF_INET;
  348.        sin.sin_addr.s_addr = htonl(INADDR_ANY);    // server accepts connections over any interface
  349.  
  350.        if ( bind(sListen, (LPSOCKADDR) &sin, sizeof(sin)) == SOCKET_ERROR )
  351.        {
  352.           DisplayWSError("Couldn't bind socket.");
  353.           closesocket(sListen);
  354.           return(TRUE);
  355.        }
  356.  
  357.        if ( listen(sListen, MAXCLIENTS) == SOCKET_ERROR )
  358.        {
  359.           DisplayWSError("Couldn't get %d sockets", MAXCLIENTS);
  360.           closesocket(sListen);
  361.           return(TRUE);
  362.        }
  363.  
  364.        /* Make the main listening socket non-blocking */
  365.  
  366.        /*
  367.         * This will cause SOCKET_MESSAGE messages to be posted
  368.         * to the Network window.
  369.         */
  370.  
  371.        if ( WSAAsyncSelect(sListen, hwndNetwork, SOCKET_MESSAGE, FD_ACCEPT) == SOCKET_ERROR )
  372.        {
  373.         DisplayWSError("Error attempting select().");
  374.         closesocket(sListen);
  375.         return(TRUE);
  376.        }
  377.  
  378.        /* Allow the sockets to be debuggable */
  379. #ifndef    NDEBUG
  380.        bDebug=TRUE;
  381.        setsockopt(sListen, SOL_SOCKET, SO_DEBUG, (char FAR *) &bDebug, sizeof(bDebug));
  382. #endif
  383.  
  384.        /* Modify the send buffer length of the sockets */
  385.        iSndSize = SENDBUFLEN;
  386.        if ( setsockopt(sListen, SOL_SOCKET, SO_SNDBUF, (char FAR *) &iSndSize, sizeof(iSndSize)) == SOCKET_ERROR)
  387.         DisplayWSError("Error setting socket SO_SNDBUF");
  388.  
  389.        /* Cannot add the socket to the list */
  390.        if ( fingerAddClient(sListen) == NULL )
  391.        {
  392.         closesocket(sListen);
  393.         return(TRUE);
  394.        }
  395.  
  396.        return(FALSE);
  397.     }
  398.  
  399.  
  400.  
  401. // Function
  402.  
  403.     void    netClose(void)
  404.  
  405. // Summary ----------------------------------------------------------------
  406. //
  407. //      Initialization for all instances of the application.  This
  408. //    registers the main window class.
  409. //
  410. //
  411. // Parameters
  412. //
  413. //      hInstance
  414. //
  415. // Return
  416. //
  417. //    BOOL    Returns FALSE if error
  418. //
  419. // Ends -------------------------------------------------------------------
  420.  
  421.     {
  422.         LPCLIENT lpClient;
  423.         LPCLIENT lpWalker;
  424.  
  425.         if (hwndNetwork != NULL)
  426.         {
  427.             lpClient = fingerClientsHead;
  428.             lpWalker = lpClient;
  429.  
  430.             while (lpClient != NULL)
  431.             {
  432.                 lpWalker = lpClient->lpNextClient;
  433.                 fingerDestroyClient(lpClient);
  434.                 lpClient = lpWalker;
  435.             }
  436.             fingerClientsHead = NULL;
  437.             DestroyWindow(hwndNetwork);
  438.             UnregisterClass((LPCSTR)szNetworkClass, hInst);
  439.             hwndNetwork = NULL;
  440.         }
  441.         WSACleanup();
  442.         return;
  443.     }
  444.  
  445.  
  446. // Function
  447.  
  448.     BOOL    netBlocking(LPCLIENT lpClient)
  449.  
  450. // Summary ----------------------------------------------------------------
  451. //
  452. //    Sets the indicated client to have a blocking socket.
  453. //
  454. // Parameters
  455. //
  456. //      lpClient    The client that we are interested in
  457. //
  458. // Return
  459. //
  460. //    BOOL    Returns TRUE if error
  461. //
  462. // Ends -------------------------------------------------------------------
  463.  
  464.  
  465.     {
  466.         u_long    nonblock = FALSE;
  467.         int    iErr;
  468.         SOCKET    sSocket;
  469.  
  470.         if ( lpClient == NULL ) return(TRUE);
  471.  
  472.         sSocket = lpClient->sSocket;
  473.  
  474.         /* Deactivate the async message notification */
  475.         if ( WSAAsyncSelect(sSocket, hwndNetwork, 0, 0) == SOCKET_ERROR)
  476.             return(TRUE);
  477.  
  478.         /* Set the socket to be blocking */
  479.         ioctlsocket(sSocket, FIONBIO, (u_long FAR*)&nonblock);
  480.  
  481.         return FALSE;
  482.     }
  483.  
  484.  
  485. // Function
  486.  
  487.     BOOL    netSelectEvents(LPCLIENT lpClient, long lEvent )
  488.  
  489. // Summary ----------------------------------------------------------------
  490. //
  491. //    Sets the indicated client to generate messages for specified
  492. //    events.  See WSAAsyncSelect for discussion of events.
  493. //
  494. // Parameters
  495. //
  496. //      lpClient    The client that we are interested in
  497. //
  498. //    lEvent        The network events that we are interested in
  499. //
  500. // Return
  501. //
  502. //    BOOL    Returns TRUE if error
  503. //
  504. // Ends -------------------------------------------------------------------
  505.  
  506.     {
  507.         SOCKET    sSocket;
  508.         int    iErr;
  509.  
  510.         if ( lpClient == NULL ) return(TRUE);
  511.  
  512.         sSocket = lpClient->sSocket;
  513.  
  514.         iErr = WSAAsyncSelect(sSocket, hwndNetwork, SOCKET_MESSAGE, lEvent);
  515.         if ( iErr == SOCKET_ERROR )
  516.         {
  517.             iErr = WSAGetLastError();
  518.             lpClient->iExtErr = iErr;
  519.             WSASetLastError(iErr);
  520.             return(TRUE);
  521.         }
  522.  
  523.         return(FALSE);
  524.     }
  525.  
  526.  
  527. // Function
  528.  
  529.     BOOL    netGetTimeAndDate(LPSTR szLine, int iLine)
  530.  
  531. // Summary ----------------------------------------------------------------
  532. //
  533. //    Returns the current system time and date using the MS-DOS clock.
  534. //    Also uses the MS-DOS "TZ" environment variable.  (ie. TZ=EST5EDT)
  535. //
  536. // Parameters
  537. //
  538. //    szLine    The buffer to place the time and date
  539. //
  540. //    iLine    The length of the buffer
  541. //
  542. // Return
  543. //
  544. //    BOOL    Returns TRUE if error
  545. //
  546. // Ends -------------------------------------------------------------------
  547.  
  548.     {
  549.         struct tm    *tmClock;
  550.         time_t        tClock;
  551. //        LPSTR        lpSysTime;
  552.         char        szTemp[256];
  553.  
  554.         /*
  555.          * Borland C++ 3.1 funtion which will read the
  556.          * TZ=EST5EDT environment variable
  557.          */
  558.         tzset();
  559.  
  560.         time(&tClock);
  561.         tmClock = localtime(&tClock);
  562.  
  563.         if ( !strftime(szTemp, sizeof(szTemp), "%a, %d %b %y %H:%M:%S %Z", tmClock))
  564.         {
  565.             /* remove the newline character from the string */
  566.             lstrcpy((LPSTR) szTemp, (LPSTR)asctime(tmClock));
  567.             szTemp[lstrlen((LPSTR)szTemp)-1] = '\0';
  568.         }
  569.  
  570.         if(lstrlen((LPSTR)szTemp) > iLine)
  571.         {
  572.             szTemp[iLine-1] = '\0';
  573.         }
  574.         lstrcpy(szLine, (LPSTR)szTemp);
  575.  
  576.         return(FALSE);
  577.     }