home *** CD-ROM | disk | FTP | other *** search
- // Contents ---------------------------------------------------------------
- //
- // net.c -- WinSock related functions
- //
- // Version 1.0, a Windows Socket Finger Daemon
- //
- // Copyright (C) Frederick W. Bent 1994
- // All rights reserved.
- //
- //
- // Description
- //
- // This file contains the networking portion of the server. The
- // server gets a socket and binds it to the finger port. listen()
- // is used to accept the connections from the clients.
- //
- // WSAAsyncSelect() is used to cause an FD_ACCEPT to be sent to the
- // network window. WSAAsyncSelect() is used to modify the
- // accepted socket so that FD_READ, FD_WRITE and FD_CLOSE messages
- // as used to notify the server about the various states of the
- // client socket.
- //
- // Ends -------------------------------------------------------------------
-
- // History ----------------------------------------------------------------
- //
- // 6/28/94 1.0 Fred Bent Started implementation
- //
- // Ends -------------------------------------------------------------------
-
- // Interface Dependencies -------------------------------------------------
-
- #define STRICT
-
- #include <windows.h>
- #include <windowsx.h>
- #include <winsock.h>
- #include <time.h>
- #include <wassert.h>
- #include "fingerd.h"
-
- #define MAXHOSTNAMELEN 64
-
- // End Interface Dependencies ---------------------------------------------
-
- // External Declarations -------------------------------------------------
-
- extern HWND hwndMain; // handle of main window
- extern HINSTANCE hInst; // our main instance
- extern char szMainBuffer[SENDBUFLEN]; // transfer buffer holds in/outbound text
- extern LPCLIENT fingerClientsHead; // linked list root
-
- // End External Declarations ----------------------------------------------
-
- // Server Implementation --------------------------------------------------
-
- SOCKET sListen; // awaits connection requests
- HWND hwndNetwork; // our invisible network "window"
- char szNetworkClass[CLASS_SIZE]; // class name of network window
- char szLocalHostName[MAXHOSTNAMELEN];
-
-
- // WindowProc Function
-
- LRESULT CALLBACK NetWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
-
- // Summary ----------------------------------------------------------------
- //
- // The network window procedure. It is used to handle the
- // SOCKET_MESSAGE posted due to network activity. This allows the
- // daemon to be asynchronous.
- //
- // Parameters
- //
- // hWnd Handle of the window.
- //
- // Msg Message.
- //
- // wParam First message paramter.
- //
- // lParam Second message parameter.
- //
- // Returns
- //
- // BOOL Returns FALSE when the message has been processed, otherwise
- // returns the result of DefWindowProc().
- //
- // Ends -------------------------------------------------------------------
-
- {
- LPCLIENT lpClient;
- SOCKET sSocket;
- SOCKADDR_IN saPeer;
- int iAddrSize;
- int iError;
-
- lpClient = NULL;
-
- switch (Msg)
- {
- case SOCKET_MESSAGE:
- {
- switch(WSAGETSELECTEVENT(lParam))
- {
- case FD_ACCEPT:
- {
- LPSOCKADDR_IN lpsaHostAddr;
- LPHOSTENT lpheHostEnt;
-
- /* Get a pending accept */
-
- iAddrSize = sizeof(SOCKADDR_IN);
- sSocket = accept( sListen, (LPSOCKADDR) &saPeer, (LPINT) &iAddrSize );
- if ( sSocket == INVALID_SOCKET )
- { DisplayWSError("Couldn't accept() connection.");
- return(FALSE);
- }
-
- /* Allocate socket specific data */
-
- lpClient = fingerAddClient(sSocket);
- if ( lpClient == NULL ) return(FALSE);
-
- /* Remember the connected Peer's address */
-
- lpClient->saPeer = saPeer;
-
- /* Get a far pointer to it...*/
- lpsaHostAddr = (LPSOCKADDR_IN) &(lpClient->saPeer);
-
- lpheHostEnt = gethostbyaddr((LPSTR)&(lpsaHostAddr->sin_addr.s_addr), 4, PF_INET);
- if ( lpheHostEnt == NULL )
- {
- /* OK, cannot find a hostname, so use the dot notation */
- lstrcpy((LPSTR)lpClient->szPeer, inet_ntoa(lpsaHostAddr->sin_addr));
- } else {
- lstrcpy((LPSTR)lpClient->szPeer, (LPSTR)(lpheHostEnt->h_name));
- }
-
- /* OK now get messages from this socket */
-
- if ( WSAAsyncSelect( sSocket, hwndNetwork
- , SOCKET_MESSAGE
- , (FD_READ | FD_CLOSE)) == SOCKET_ERROR)
- {
- DisplayWSError("Couldn't select() on client socket.");
- fingerDestroyClient(lpClient);
- return(FALSE);
- }
-
- fingerLog(DEBUG_HIGH | LOG_TIME, IDS_CONNECT_S, (LPSTR) lpClient->szPeer, sSocket);
-
- return(FALSE);
- } // FD_ACCEPT
-
-
- case FD_READ: // WinSock has something for us
- {
- int iError;
-
- /* Find the corresponding client */
-
- lpClient = fingerSocketToClient((SOCKET) wParam);
- if (lpClient == NULL) return(FALSE);
-
- #ifdef WINSOCK_BUG
- if ( netSelectEvents(lpClient, (FD_WRITE | FD_CLOSE)) )
- return (FALSE);
- #endif
-
- /* Attempt to get the data from this client */
-
- if ( fingerServer(lpClient) )
- {
- if ( lpClient->iState == STATE_WSERROR )
- {
- WSASetLastError(lpClient->iExtErr);
- DisplayWSError("");
- }
- fingerDestroyClient(lpClient);
- return(FALSE);
- }
-
- #ifdef WINSOCK_BUG
- if ( netSelectEvents(lpClient, (FD_READ | FD_WRITE | FD_CLOSE)) )
- {
- DisplayWSError("");
- fingerDestroyClient(lpClient);
- }
- #endif
-
- return(FALSE);
- } // FD_READ
-
-
- case FD_WRITE: // WinSock ready to send data on this socket
- {
- lpClient = fingerSocketToClient((SOCKET) wParam);
- if (lpClient == NULL) return(FALSE);
-
- #ifdef WINSOCK_BUG
- if ( netSelectEvents(lpClient, (FD_READ | FD_CLOSE)))
- {
- DisplayWSError("");
- fingerDestroyClient(lpClient);
- return(FALSE);
- }
- #endif
-
- if ( !fingerSendFile(lpClient) )
- {
- fingerDestroyClient(lpClient);
- return(FALSE);
- }
- #ifdef WINSOCK_BUG
- if ( netSelectEvents(lpClient, (FD_READ | FD_WRITE | FD_CLOSE)))
- {
- DisplayWSError("");
- fingerDestroyClient(lpClient);
- }
- #endif
-
- return(FALSE);
- } // FD_WRITE
-
-
- case FD_CLOSE: // Hey, it closed on us...
- {
- lpClient = fingerSocketToClient((SOCKET) wParam);
- if (lpClient == NULL) return(FALSE);
-
- fingerDestroyClient(lpClient);
- return(FALSE);
- } // FD_CLOSE
-
- default: // Should never get here!!!
- break;
- }
- } // SOCKET_MESSAGE
-
- case WM_CLOSE: // Network window being closed...
- {
- fingerDestroyClient(fingerClientsHead);
- fingerClientsHead = NULL;
- WSACleanup();
- return(FALSE);
- } // WM_CLOSE
- }
-
- return(DefWindowProc(hWnd,Msg,wParam,lParam));
- }
-
-
- // Function
-
- BOOL netInit(void)
-
- // Summary ----------------------------------------------------------------
- //
- // Creates the network windows, which is a child of hwndMain. The
- // main socket that listens for client connections (sListen) is also
- // created. This socket will affect the clients that are accept().
- //
- // Parameters
- //
- // none
- //
- // Return
- //
- // BOOL Returns FALSE if error
- //
- // Ends -------------------------------------------------------------------
-
- {
- WNDCLASS wndclass;
- SOCKADDR_IN sin;
- LPSERVENT lpseServEnt;
- LPHOSTENT lpheHostEnt;
- BOOL bDebug;
- int iSndSize;
-
-
- /* Get the local host name and save it */
- if (gethostname((LPSTR)szLocalHostName, sizeof(szLocalHostName)) == SOCKET_ERROR)
- {
- lstrcpy((LPSTR) szLocalHostName, (LPSTR) STRING_UNKNOWN);
- } else {
- lpheHostEnt = gethostbyname((LPSTR)szLocalHostName);
- if (lpheHostEnt != NULL)
- {
- lstrcpy((LPSTR) szLocalHostName, lpheHostEnt->h_name);
- }
- }
- /*
- * Setup the invisible network window which will get the
- * WinSock messages
- */
-
- wndclass.style = 0;
- wndclass.lpfnWndProc = NetWndProc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = 0;
- wndclass.hInstance = hInst; // Owned
- wndclass.hIcon = NULL;
- wndclass.hCursor = NULL;
- wndclass.hbrBackground = NULL;
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = szNetworkClass;
-
- if (!RegisterClass(&wndclass)) return(TRUE);
-
- hwndNetwork = CreateWindow( (LPSTR)szNetworkClass, NULL
- , WS_CHILD
- , CW_USEDEFAULT, CW_USEDEFAULT
- , CW_USEDEFAULT, CW_USEDEFAULT
- , hwndMain
- , NULL
- , hInst
- , NULL);
-
- if (hwndNetwork == NULL)
- {
- UnregisterClass((LPSTR)szNetworkClass, hInst);
- return(TRUE);
- }
-
-
- /* Make a stream-socket */
- sListen = socket(AF_INET, SOCK_STREAM, 0);
- if( sListen == INVALID_SOCKET )
- {
- DisplayWSError("Couldn't make socket.");
- return(TRUE);
- }
-
- /* Attempt to find an entry for "finger", "tcp" */
- lpseServEnt = getservbyname((LPSTR)FINGER_NAME, NULL);
- if (lpseServEnt == NULL)
- {
- /* Couldn't find one, so use hard coded value... */
- DisplayWSError("Couldn't resolve FINGER service port.");
- sin.sin_port = htons(FINGER_PORT);
- } else {
- sin.sin_port = lpseServEnt->s_port;
- }
-
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = htonl(INADDR_ANY); // server accepts connections over any interface
-
- if ( bind(sListen, (LPSOCKADDR) &sin, sizeof(sin)) == SOCKET_ERROR )
- {
- DisplayWSError("Couldn't bind socket.");
- closesocket(sListen);
- return(TRUE);
- }
-
- if ( listen(sListen, MAXCLIENTS) == SOCKET_ERROR )
- {
- DisplayWSError("Couldn't get %d sockets", MAXCLIENTS);
- closesocket(sListen);
- return(TRUE);
- }
-
- /* Make the main listening socket non-blocking */
-
- /*
- * This will cause SOCKET_MESSAGE messages to be posted
- * to the Network window.
- */
-
- if ( WSAAsyncSelect(sListen, hwndNetwork, SOCKET_MESSAGE, FD_ACCEPT) == SOCKET_ERROR )
- {
- DisplayWSError("Error attempting select().");
- closesocket(sListen);
- return(TRUE);
- }
-
- /* Allow the sockets to be debuggable */
- #ifndef NDEBUG
- bDebug=TRUE;
- setsockopt(sListen, SOL_SOCKET, SO_DEBUG, (char FAR *) &bDebug, sizeof(bDebug));
- #endif
-
- /* Modify the send buffer length of the sockets */
- iSndSize = SENDBUFLEN;
- if ( setsockopt(sListen, SOL_SOCKET, SO_SNDBUF, (char FAR *) &iSndSize, sizeof(iSndSize)) == SOCKET_ERROR)
- DisplayWSError("Error setting socket SO_SNDBUF");
-
- /* Cannot add the socket to the list */
- if ( fingerAddClient(sListen) == NULL )
- {
- closesocket(sListen);
- return(TRUE);
- }
-
- return(FALSE);
- }
-
-
-
- // Function
-
- void netClose(void)
-
- // Summary ----------------------------------------------------------------
- //
- // Initialization for all instances of the application. This
- // registers the main window class.
- //
- //
- // Parameters
- //
- // hInstance
- //
- // Return
- //
- // BOOL Returns FALSE if error
- //
- // Ends -------------------------------------------------------------------
-
- {
- LPCLIENT lpClient;
- LPCLIENT lpWalker;
-
- if (hwndNetwork != NULL)
- {
- lpClient = fingerClientsHead;
- lpWalker = lpClient;
-
- while (lpClient != NULL)
- {
- lpWalker = lpClient->lpNextClient;
- fingerDestroyClient(lpClient);
- lpClient = lpWalker;
- }
- fingerClientsHead = NULL;
- DestroyWindow(hwndNetwork);
- UnregisterClass((LPCSTR)szNetworkClass, hInst);
- hwndNetwork = NULL;
- }
- WSACleanup();
- return;
- }
-
-
- // Function
-
- BOOL netBlocking(LPCLIENT lpClient)
-
- // Summary ----------------------------------------------------------------
- //
- // Sets the indicated client to have a blocking socket.
- //
- // Parameters
- //
- // lpClient The client that we are interested in
- //
- // Return
- //
- // BOOL Returns TRUE if error
- //
- // Ends -------------------------------------------------------------------
-
-
- {
- u_long nonblock = FALSE;
- int iErr;
- SOCKET sSocket;
-
- if ( lpClient == NULL ) return(TRUE);
-
- sSocket = lpClient->sSocket;
-
- /* Deactivate the async message notification */
- if ( WSAAsyncSelect(sSocket, hwndNetwork, 0, 0) == SOCKET_ERROR)
- return(TRUE);
-
- /* Set the socket to be blocking */
- ioctlsocket(sSocket, FIONBIO, (u_long FAR*)&nonblock);
-
- return FALSE;
- }
-
-
- // Function
-
- BOOL netSelectEvents(LPCLIENT lpClient, long lEvent )
-
- // Summary ----------------------------------------------------------------
- //
- // Sets the indicated client to generate messages for specified
- // events. See WSAAsyncSelect for discussion of events.
- //
- // Parameters
- //
- // lpClient The client that we are interested in
- //
- // lEvent The network events that we are interested in
- //
- // Return
- //
- // BOOL Returns TRUE if error
- //
- // Ends -------------------------------------------------------------------
-
- {
- SOCKET sSocket;
- int iErr;
-
- if ( lpClient == NULL ) return(TRUE);
-
- sSocket = lpClient->sSocket;
-
- iErr = WSAAsyncSelect(sSocket, hwndNetwork, SOCKET_MESSAGE, lEvent);
- if ( iErr == SOCKET_ERROR )
- {
- iErr = WSAGetLastError();
- lpClient->iExtErr = iErr;
- WSASetLastError(iErr);
- return(TRUE);
- }
-
- return(FALSE);
- }
-
-
- // Function
-
- BOOL netGetTimeAndDate(LPSTR szLine, int iLine)
-
- // Summary ----------------------------------------------------------------
- //
- // Returns the current system time and date using the MS-DOS clock.
- // Also uses the MS-DOS "TZ" environment variable. (ie. TZ=EST5EDT)
- //
- // Parameters
- //
- // szLine The buffer to place the time and date
- //
- // iLine The length of the buffer
- //
- // Return
- //
- // BOOL Returns TRUE if error
- //
- // Ends -------------------------------------------------------------------
-
- {
- struct tm *tmClock;
- time_t tClock;
- // LPSTR lpSysTime;
- char szTemp[256];
-
- /*
- * Borland C++ 3.1 funtion which will read the
- * TZ=EST5EDT environment variable
- */
- tzset();
-
- time(&tClock);
- tmClock = localtime(&tClock);
-
- if ( !strftime(szTemp, sizeof(szTemp), "%a, %d %b %y %H:%M:%S %Z", tmClock))
- {
- /* remove the newline character from the string */
- lstrcpy((LPSTR) szTemp, (LPSTR)asctime(tmClock));
- szTemp[lstrlen((LPSTR)szTemp)-1] = '\0';
- }
-
- if(lstrlen((LPSTR)szTemp) > iLine)
- {
- szTemp[iLine-1] = '\0';
- }
- lstrcpy(szLine, (LPSTR)szTemp);
-
- return(FALSE);
- }