/*@@ @file Sockets.c @date Wed Sep 13 20:39:15 2000 @author Tom Goodale @desc Routines which deal with sockets. These should probably move into thorn Socket at some point if they aren't already there. @enddesc @version $Header$ @@*/ #include "cctk.h" #include #include #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ #ifdef HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ #ifdef HAVE_SYS_TYPES_H #include #endif /* HAVE_SYS_TYPES_H */ #ifdef HAVE_SYS_SOCKET_H #include #endif /* HAVE_SYS_SOCKET_H */ #ifdef HAVE_NETINET_IN_H #include #endif /* HAVE_NETINET_IN_H */ #ifdef HAVE_NETDB_H #include #endif /* HAVE_NETDB_H */ #ifdef HAVE_ARPA_INET_H #include #endif /* ARPA_INET_H */ #ifdef HAVE_WINSOCK2_H #include #endif /* HAVE_WINSOCK2_H */ #include "httpd.h" static char *rcsid = "$Header$"; CCTK_FILEVERSION(DevThorns_httpd_Socket_c) /******************************************************************** ********************* Local Data Types *********************** ********************************************************************/ #ifndef SOCKET #define SOCKET int #endif #ifdef SOCKET_ERROR #define ERROR_CHECK(a) ((a) == SOCKET_ERROR) #else #define ERROR_CHECK(a) ((a) < 0) #endif #ifdef HAVE_WINSOCK2_H #define CLOSESOCKET(a) closesocket(a) #else #define CLOSESOCKET(a) close(a) #endif /******************************************************************** ********************* Local Routine Prototypes ********************* ********************************************************************/ SOCKET HTTP_MakeSocket (unsigned long port); static int InitialiseTCP(void); /******************************************************************** ********************* Other Routine Prototypes ********************* ********************************************************************/ /******************************************************************** ********************* Local Data ***************************** ********************************************************************/ /* Active file descriptors */ static fd_set active_fd_set; /* Main server socket */ static SOCKET sock; static SOCKET minsock; static SOCKET maxsock; /******************************************************************** ********************* External Routines ********************** ********************************************************************/ /*@@ @routine HTTP_SetupServer @date Wed Sep 13 20:39:15 2000 @author Tom Goodale @desc Creates a socket to listen on. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_SetupServer(int port, int queue_size) { /* Some systems need special logic for starting up TCP. */ InitialiseTCP(); /* Create the socket and set it up to accept connections. */ sock = HTTP_MakeSocket (port); if (ERROR_CHECK(listen (sock, queue_size))) { perror ("listen"); exit (EXIT_FAILURE); } minsock = sock; maxsock = sock; /* Initialize the set of active sockets. */ FD_ZERO (&active_fd_set); FD_SET (sock, &active_fd_set); return 0; } /*@@ @routine HTTP_ShutdownServer @date Wed Sep 13 20:39:15 2000 @author Tom Goodale @desc Closes all sockets we are interested in. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_ShutdownServer(void) { unsigned int i; /* Close all sockets in our active set */ for(i = maxsock; i >= minsock; i--) { if(FD_ISSET(i, &active_fd_set)) { CLOSESOCKET(i); } } return 0; } /*@@ @routine HTTP_Poll @date Wed Sep 13 20:39:15 2000 @author Tom Goodale @desc Main workhorse routine. Looks for activity on any of the sockets which are open and dispatches work. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_Poll(cGH *cctkGH, long sec, long usec) { unsigned int i; #ifdef HAVE_SOCKLEN_T socklen_t size; #else int size; #endif fd_set read_fd_set; struct sockaddr_in clientname; struct timeval timeout; struct timeval *real_timeout; if(sec >=0) { timeout.tv_sec = sec; timeout.tv_usec = usec; real_timeout = &timeout; } else { real_timeout = NULL; } /* Check if any input is available on one or more active sockets. */ read_fd_set = active_fd_set; if (ERROR_CHECK(select (FD_SETSIZE, &read_fd_set, NULL, NULL, real_timeout))) { perror ("select"); CCTK_Abort(cctkGH, EXIT_FAILURE); } /* Service all the sockets with input pending. */ for (i = minsock; i <= maxsock; ++i) { if (FD_ISSET (i, &read_fd_set)) { if (i == sock) { /* Connection request on original socket. */ SOCKET new; size = sizeof (clientname); new = accept (sock, (struct sockaddr *) &clientname, &size); if (ERROR_CHECK(new)) { perror ("accept"); CCTK_Abort(cctkGH, EXIT_FAILURE); } fprintf (stderr, "Server: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port)); FD_SET (new, &active_fd_set); if(new > maxsock) { maxsock = new; } if(new < minsock) { minsock = new; } } else { /* Data arriving on an already-connected socket. */ if (HTTP_ReadFromClient (cctkGH, i) < 0) { CLOSESOCKET(i); FD_CLR (i, &active_fd_set); } } } } return 0; } /*@@ @routine HTTP_Write @date Fri Sep 15 18:47:41 2000 @author Tom Goodale @desc Writes part or all of an HTTP reply. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_Write(httpRequest *request, const char *buffer, size_t count) { int retval; /* Currently don't do anything fancy. */ retval = send(request->filedes, buffer, count,0); return retval; } /*@@ @routine HTTP_Read @date Mon Sep 18 10:14:03 2000 @author Tom Goodale @desc Reads part or all of an HTTP request. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_Read(httpRequest *request, char *buffer, size_t count) { int retval; /* Currently don't do anything fancy. */ retval = recv(request->filedes, buffer, count,0); return retval; } /******************************************************************** ********************* Local Routines ************************* ********************************************************************/ /*@@ @routine HTTP_MakeSocket @date Wed Sep 13 20:39:15 2000 @author Tom Goodale @desc Creates a socket. @enddesc @calls @calledby @history @endhistory @@*/ int HTTP_MakeSocket (unsigned long port) { int sock; struct sockaddr_in name; int opt; /* Create the socket. */ sock = socket (PF_INET, SOCK_STREAM, 0); if (ERROR_CHECK(sock)) { perror ("socket"); CCTK_Abort(NULL, EXIT_FAILURE); } /* Try to reuse the port if possible */ #ifdef SO_REUSEADDR opt = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #endif /* Give the socket a name. */ name.sin_family = AF_INET; name.sin_port = htons (port); name.sin_addr.s_addr = htonl (INADDR_ANY); if (ERROR_CHECK(bind (sock, (struct sockaddr *) &name, sizeof (name)))) { perror ("bind"); CCTK_Abort(NULL,EXIT_FAILURE); } return sock; } /****************************************************************************** ****************************************************************************** ******************************************************************************/ /* Special code for starting up the socket layer. */ #ifdef HAVE_WINSOCK2_H #ifndef _M_IX86 #define _M_IX86 400 #endif #include #include #include static int InitialiseTCP(void) { WORD wVersionRequested; WSADATA wsaData; int errnumber; wVersionRequested = MAKEWORD( 2, 0 ); errnumber = WSAStartup( wVersionRequested, &wsaData ); if (errnumber) { fprintf(stderr, "Couldn't start Windows socket layer\n"); } else { printf("Windows socket layer initialized."); } return errnumber; } #else static int InitialiseTCP(void) { return 0; } #endif /* defined HAVE_WINSOCK2_H */