diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Sockets.c | 283 | ||||
-rw-r--r-- | src/http.c | 8 | ||||
-rw-r--r-- | src/http_Request.h | 4 | ||||
-rw-r--r-- | src/httpd.h | 2 |
4 files changed, 250 insertions, 47 deletions
diff --git a/src/Sockets.c b/src/Sockets.c index 1984531..601e834 100644 --- a/src/Sockets.c +++ b/src/Sockets.c @@ -38,6 +38,7 @@ #ifdef HAVE_WINSOCK2_H #include <winsock2.h> #endif /* HAVE_WINSOCK2_H */ +#include <errno.h> #include "httpd.h" @@ -65,12 +66,26 @@ CCTK_FILEVERSION(DevThorns_httpd_Socket_c) #define CLOSESOCKET(a) close(a) #endif +typedef enum {closed, open} httpSocketState; + +typedef struct HTTPSocket +{ + struct HTTPSocket *prev; + struct HTTPSocket *next; + unsigned long filedes; + httpSocketState state; +} httpSocket; + /******************************************************************** ********************* Local Routine Prototypes ********************* ********************************************************************/ SOCKET HTTP_MakeSocket (unsigned long port); +static httpSocket *SocketCreate(unsigned long int filedes); +static void SocketDestroy(httpSocket *this); +static void SocketClose(httpSocket *this); + static int InitialiseTCP(void); /******************************************************************** @@ -89,6 +104,8 @@ static SOCKET sock; static SOCKET minsock; static SOCKET maxsock; +static httpSocket *socklist = NULL; + /******************************************************************** ********************* External Routines ********************** ********************************************************************/ @@ -193,6 +210,9 @@ int HTTP_Poll(cGH *cctkGH, long sec, long usec) struct timeval timeout; struct timeval *real_timeout; + httpSocket *this; + httpSocket *next; + if(sec >=0) { timeout.tv_sec = sec; @@ -215,50 +235,41 @@ int HTTP_Poll(cGH *cctkGH, long sec, long usec) } /* Service all the sockets with input pending. */ - for (i = minsock; i <= maxsock; ++i) + if (FD_ISSET (sock, &read_fd_set)) { - if (FD_ISSET (i, &read_fd_set)) + /* Connection request on original socket. */ + SOCKET new; + size = sizeof (clientname); + new = accept (sock, + (struct sockaddr *) &clientname, + &size); + if (ERROR_CHECK(new)) { - 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); + 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)); - if(new > maxsock) - { - maxsock = new; - } - if(new < minsock) - { - minsock = new; - } - } - else + SocketCreate(new); + } + + for(this = socklist; this; this = next) + { + next = this->next; + if(FD_ISSET (this->filedes, &read_fd_set)) + { + /* Data arriving on an already-connected socket. */ + if (HTTP_ReadFromClient (cctkGH, this) < 0) { - /* Data arriving on an already-connected socket. */ - if (HTTP_ReadFromClient (cctkGH, i) < 0) - { - CLOSESOCKET(i); - FD_CLR (i, &active_fd_set); - } + SocketDestroy(this); } } } + return 0; } @@ -279,9 +290,128 @@ int HTTP_Poll(cGH *cctkGH, long sec, long usec) 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); + int bytes_sent; + size_t halfcount; + httpSocket *connection; + int done; + int tmp; + fd_set this_set; + + + connection = (httpSocket *)request->connection; + + if(connection->state = open) + { + FD_ZERO (&this_set); + done = 0; + bytes_sent = 0; + while(!done) + { + /* Try and send the data. Make sure we don't get a SIGPIPE if the + * other end is closed. + */ + retval = send(connection->filedes, + buffer+bytes_sent, + count-bytes_sent, + MSG_NOSIGNAL); + + /* Check for errors */ + if(retval == -1) + { + switch(errno) + { + case EMSGSIZE : /* The socket requires that message be sent atomically, + * and the size of the message to be sent made this + * impossible. + */ + /* Split message in two and try again. */ + halfcount = count/2; + retval = HTTP_Write(request, buffer, halfcount); + if(retval > -1) + { + tmp = HTTP_Write(request, buffer+halfcount, count-halfcount); + } + if(tmp > -1) + { + retval += tmp; + } + else + { + retval = tmp; + } + break; + + case ENOBUFS : + /* The output queue for a network interface was full. This generally indicates that the interface has + * stopped sending, but may be caused by transient congestion. (This cannot occur in Linux, packets are + * just silently dropped when a device queue overflows.) + */ + retval = 0; + break; + + case EBADF : /* An invalid descriptor was specified. */ + + case ENOTSOCK : /* The filedescriptor is not a socket. */ + case EPIPE : /* The local end has been shut down on a connection oriented socket. In this case the process will also + * receive a SIGPIPE unless MSG_NOSIGNAL is set. + */ + SocketClose(connection); + break; + + case EINTR : /* A signal occurred.*/ + + case ENOMEM : /* No memory available. */ + + case EINVAL : /* Invalid argument passed. */ + + case EFAULT : /* An invalid user space address was specified for a parameter. */ + break; + +#if 0 + case EAGAIN : + case EWOULDBLOCK : + /* The socket is marked non-blocking and the requested operation would block. */ +#endif + default : + fprintf(stderr, "Error: this should never happen - %s %d", __FILE__, __LINE__); + } + } + else + { + bytes_sent += retval; + } + + if(retval > -1 && bytes_sent < count) + { + /* Wait until can write */ + FD_SET (connection->filedes, &this_set); + if (ERROR_CHECK(select (FD_SETSIZE, NULL, &this_set, NULL, NULL))) + { + perror ("select"); + CCTK_Abort(NULL, EXIT_FAILURE); + } + } + else + { + done = 1; + } + }; + } + else + { + retval = -1; + } + +#ifdef HTTP_DEBUG + if(retval != -1) + { + fprintf (stderr, "Wrote: `%s'\n", buffer); + } + else + { + fprintf(stderr, "Couldn't write to the socket 8-(\n"); + } +#endif return retval; } @@ -304,8 +434,16 @@ int HTTP_Read(httpRequest *request, char *buffer, size_t count) { int retval; + httpSocket *connection; + + connection = (httpSocket *)request->connection; + /* Currently don't do anything fancy. */ - retval = recv(request->filedes, buffer, count,0); + retval = recv(connection->filedes, buffer, count,0); + +#ifdef HTTP_DEBUG + fprintf (stderr, "Read: `%s'\n", buffer); +#endif return retval; } @@ -361,6 +499,71 @@ int HTTP_MakeSocket (unsigned long port) return sock; } +static httpSocket *SocketCreate(unsigned long int filedes) +{ + httpSocket *this; + + this = (httpSocket *)malloc(sizeof (httpSocket)); + + if(this) + { + this->filedes = filedes; + this->state = open; + this->prev = NULL; + this->next = socklist; + + if(socklist) + { + socklist->prev = this; + } + + socklist = this; + + FD_SET (this->filedes, &active_fd_set); + } + + return this; +} + +static void SocketDestroy(httpSocket *this) +{ + if(this) + { + if(this->state = open) + { + SocketClose(this); + } + + if(this->next) + { + this->next->prev = this->prev; + } + + if(this->prev) + { + this->prev->next=this->next; + } + else + { + socklist = this->next; + } + + free(this); + } +} + +static void SocketClose(httpSocket *this) +{ + if(this) + { + if(this->state = open) + { + CLOSESOCKET(this->filedes); + this->state=closed; + FD_CLR (this->filedes, &active_fd_set); + } + } +} /****************************************************************************** ****************************************************************************** @@ -77,7 +77,7 @@ static void DestroyArgument(httpArg *argument); @endhistory @@*/ -int HTTP_ReadFromClient(cGH *cctkGH, int filedes) +int HTTP_ReadFromClient(cGH *cctkGH, void *connection) { int retval; int keepalive; @@ -87,14 +87,14 @@ int HTTP_ReadFromClient(cGH *cctkGH, int filedes) InitialiseRequest(&request); - request.filedes = filedes; + request.connection = connection; nbytes = HTTP_Read(&request, buffer, MAXMSG); if (nbytes < 0) { /* Read error. */ - perror ("read"); + perror ("HTTP_Read"); CCTK_Abort(cctkGH, EXIT_FAILURE); } else if (nbytes == 0) @@ -669,7 +669,7 @@ static int InitialiseRequest(httpRequest *request) /* Initialise the private data */ - request->filedes = -1; + request->connection = NULL; request->headers = NULL; request->arguments = NULL; diff --git a/src/http_Request.h b/src/http_Request.h index 4e1d370..741af4c 100644 --- a/src/http_Request.h +++ b/src/http_Request.h @@ -44,8 +44,8 @@ typedef struct /* These are all private members of this structure */ - /* The file descriptor */ - int filedes; + /* The connection data */ + void *connection; /* The request header lines */ uHash *headers; diff --git a/src/httpd.h b/src/httpd.h index 522f0f5..7f76643 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -27,7 +27,7 @@ extern "C" { #endif -int HTTP_ReadFromClient (cGH *cctkGH, int filedes); +int HTTP_ReadFromClient (cGH *cctkGH, void *connection); int HTTP_SetupServer(int port, int queue_size); |