aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgoodale <goodale@1faa4e14-9dd3-4be0-9f0e-ffe519881164>2000-09-21 09:31:12 +0000
committergoodale <goodale@1faa4e14-9dd3-4be0-9f0e-ffe519881164>2000-09-21 09:31:12 +0000
commit1332446b87c6822bbc1ffdc0db2fb3e409749203 (patch)
tree09e6f97410704c02c2ea1d0726f90c8f7de3180c
parentdb8e32396434e839819e65add9747f4038b7bcbf (diff)
Reworked the socket layer a bit to detect errors when writing to a socket and
take appropriate action. Now it marks the socket closed on most errors, waits till it can write if the buffer is full, or splits the message up if the message was too big for the socket. Tom git-svn-id: http://svn.cactuscode.org/arrangements/CactusConnect/HTTPD/trunk@72 1faa4e14-9dd3-4be0-9f0e-ffe519881164
-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);