aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Sockets.c283
-rw-r--r--src/http.c8
-rw-r--r--src/http_Request.h4
-rw-r--r--src/httpd.h2
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);
+ }
+ }
+}
/******************************************************************************
******************************************************************************
diff --git a/src/http.c b/src/http.c
index a428233..d97d779 100644
--- a/src/http.c
+++ b/src/http.c
@@ -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);