From 228b1d0d29b12379a20ec0d950fd76d3b0b1021d Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Wed, 8 Feb 2012 10:21:04 +0100 Subject: [PATCH] changed request handling. @TODO: I still seem to have the problem that the file handles are not closed and freed correctly as the service refuses connections after about a 1000. --- ChangeLog | 10 ++- include/server.h | 13 +++- src/http/request_parser.c | 7 -- src/server/close_conn.c | 12 ++-- src/server/handle_accept.c | 32 ++++----- src/server/poll.c | 28 ++++++++ src/server/read.c | 56 +++++++-------- src/server/run.c | 137 +++++++++++++++++++++++-------------- src/socket.c | 9 ++- src/socket/accept.c | 2 +- src/testserver.c | 1 + 11 files changed, 193 insertions(+), 114 deletions(-) diff --git a/ChangeLog b/ChangeLog index 19f810d..54d131c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ +2012-02-08 10:21:04 +0100 Georg Hopp + + * changed request handling. @TODO: I still seem to have the problem that the file handles are not closed and freed correctly as the service refuses connections after about a 1000. (HEAD, master) + +2012-02-07 14:20:00 +0100 Georg Hopp + + * now stuff seems to work correct even if read does not provide a complete request (tested with telnet) + 2012-02-07 13:41:49 +0100 Georg Hopp - * now each HttpRequestParser initializes its own request queue and enqueus completed requests there. The server now gets the queue and prints completed requests. (HEAD, master) + * now each HttpRequestParser initializes its own request queue and enqueus completed requests there. The server now gets the queue and prints completed requests. 2012-02-07 11:12:30 +0100 Georg Hopp diff --git a/include/server.h b/include/server.h index 6e05641..0fbcc9f 100644 --- a/include/server.h +++ b/include/server.h @@ -21,21 +21,28 @@ MOVE_SIZE(sizeof(((server)->conns)[0]),(idx))) -typedef void (*server_read_hook)(const char *, size_t); - CLASS(Server) { Logger logger; Sock sock; void * reader; + /** + * loeschen: fds[i].event auf 0 + * dann nfds um die anzahl der geloeschten elemente verkleinern. + * die in close pending stehenden socket schliessen. + * vor jedem poll qsort auf fds ueber event. + * nach dem poll qsort auf fds ueber revent und reuckgebewert + * von poll beruecksichtigen. + */ nfds_t nfds; + nfds_t ndel; struct pollfd fds[POLL_FD_NSIZE]; struct { Sock sock; void * reader; - char * wbuf; + char wbuf[2048]; char * rbuf; unsigned int rpos; unsigned int wpos; diff --git a/src/http/request_parser.c b/src/http/request_parser.c index 008e850..50c7842 100644 --- a/src/http/request_parser.c +++ b/src/http/request_parser.c @@ -142,7 +142,6 @@ httpRequestParserParse(HttpRequestParser this) while(cont) { switch(this->state) { case HTTP_REQUEST_GARBAGE: - puts("==skip garbage=="); data = this->buffer; // initialize static pointer httpRequestSkip(&data); request = new(HttpRequest); @@ -151,7 +150,6 @@ httpRequestParserParse(HttpRequestParser this) break; case HTTP_REQUEST_START: - puts("==request line=="); if (NULL == (line = httpRequestLineGet(&data))) { cont = 0; break; @@ -193,7 +191,6 @@ httpRequestParserParse(HttpRequestParser this) break; case HTTP_REQUEST_REQUEST_LINE_DONE: - puts("==read header=="); if (NULL == (line = httpRequestLineGet(&data))) { cont = 0; break; @@ -222,8 +219,6 @@ httpRequestParserParse(HttpRequestParser this) break; case HTTP_REQUEST_HEADERS_DONE: - puts("==headers done=="); - /** * @TODO: here comes the body handling */ @@ -231,8 +226,6 @@ httpRequestParserParse(HttpRequestParser this) break; case HTTP_REQUEST_DONE: - puts("==request done=="); - /** * enqueue current request */ diff --git a/src/server/close_conn.c b/src/server/close_conn.c index 9e4631d..00b8b5c 100644 --- a/src/server/close_conn.c +++ b/src/server/close_conn.c @@ -6,10 +6,14 @@ void serverCloseConn(Server this, unsigned int i) { - delete(&((this->conns)[i].sock)); - delete(&((this->conns)[i].reader)); - CLEAR_CONN(this, i); - this->nfds--; + int fd = (this->fds)[i].fd; + + delete(&((this->conns)[fd].sock)); + delete(&((this->conns)[fd].reader)); + (this->fds)[i].events = 0; + this->ndel++; +// CLEAR_CONN(this, i); +// this->nfds--; } // vim: set ts=4 sw=4: diff --git a/src/server/handle_accept.c b/src/server/handle_accept.c index 7a22216..a86ab13 100644 --- a/src/server/handle_accept.c +++ b/src/server/handle_accept.c @@ -2,28 +2,26 @@ static void serverHandleAccept(Server this) { - if (0 != ((this->fds)[0].revents & POLLIN)) { - char remoteAddr[16] = ""; - Sock acc; + char remoteAddr[16] = ""; + Sock acc; - acc = socketAccept(this->sock, remoteAddr); + acc = socketAccept(this->sock, remoteAddr); - if (-1 != acc->handle) { - //* save the socket handle - (this->conns)[this->nfds].sock = acc; + if (-1 != acc->handle) { + //* save the socket handle + (this->conns)[acc->handle].sock = acc; - //* clone reader - (this->conns)[this->nfds].reader = clone(this->reader); + //* clone reader + (this->conns)[acc->handle].reader = clone(this->reader); - (this->fds)[this->nfds].fd = acc->handle; - (this->fds)[this->nfds].events = POLLIN; - this->nfds++; - } else { - delete(&acc); - } - - (this->fds)[0].revents |= POLLIN; + (this->fds)[this->nfds].fd = acc->handle; + (this->fds)[this->nfds].events = POLLIN; + this->nfds++; + } else { + delete(&acc); } + + (this->fds)[0].revents |= POLLIN; } // vim: set ts=4 sw=4: diff --git a/src/server/poll.c b/src/server/poll.c index 7b64bce..f6829df 100644 --- a/src/server/poll.c +++ b/src/server/poll.c @@ -1,8 +1,34 @@ +#define POLLFD(ptr) ((struct pollfd *)(ptr)) + +static +inline +int +sortEvents(const void * a, const void * b) +{ + return POLLFD(a)->events > POLLFD(b)->events ? + -1 : POLLFD(a)->events < POLLFD(b)->events ? + 1 : 0; +} + +static +inline +int +sortRevents(const void * a, const void * b) +{ + return POLLFD(a)->revents > POLLFD(b)->revents ? + -1 : POLLFD(a)->revents < POLLFD(b)->revents ? + 1 : 0; +} + static int serverPoll(Server this) { int events; + qsort(this->fds, this->nfds, sizeof(struct pollfd), sortEvents); + this->nfds -= this->ndel; + this->ndel = 0; + /* * wait for handles to become ready */ @@ -23,6 +49,8 @@ serverPoll(Server this) { } } + qsort(this->fds, this->nfds, sizeof(struct pollfd), sortRevents); + return events; } diff --git a/src/server/read.c b/src/server/read.c index 56c066f..fc00c27 100644 --- a/src/server/read.c +++ b/src/server/read.c @@ -1,41 +1,37 @@ static int -serverRead(Server this) +serverRead(Server this, unsigned int i) { - unsigned int i; + int fd = (this->fds)[i].fd; - for (i=1; infds; i++) { - if (0 != ((this->fds)[i].revents & POLLIN)) { - if (NULL == (this->conns)[i].reader) { - loggerLog( - this->logger, - LOGGER_INFO, - "initialization error: NULL reader"); - serverCloseConn(this, i); - } + if (NULL == (this->conns)[fd].reader) { + loggerLog( + this->logger, + LOGGER_INFO, + "initialization error: NULL reader"); + serverCloseConn(this, i); + } - switch (streamReaderRead((this->conns)[i].reader, (this->fds)[i].fd)) { - case 0: - /* - * normal close: write remaining data - * @TODO: actually we have no remaining data here.... - */ - /* DROP-THROUGH */ + switch (streamReaderRead((this->conns)[fd].reader, fd)) { + case 0: + /* + * normal close: write remaining data + * @TODO: actually we have no remaining data here.... + */ + /* DROP-THROUGH */ - case -1: - /* - * read failure / close connection - */ - loggerLog(this->logger, LOGGER_INFO, "connection closed..."); - serverCloseConn(this, i); - break; + case -1: + /* + * read failure / close connection + */ + loggerLog(this->logger, LOGGER_INFO, "connection closed..."); + serverCloseConn(this, i); + break; - default: - break; - } - } + default: + break; } - + return 0; } diff --git a/src/server/run.c b/src/server/run.c index 18897b4..fb0958f 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -3,6 +3,7 @@ #include /* for exit */ #include /* for errno */ #include +#include #include "server.h" #include "socket.h" @@ -42,64 +43,100 @@ serverRun(Server this) */ while (!doShutdown) /* until error or signal */ { - int events; + int events; + unsigned int i; - /** - * @TODO take return value of poll into account with - * further handling! - */ events = serverPoll(this); if (doShutdown) break; - /** - * handle accept - */ - serverHandleAccept(this); - - /** - * handle reads - */ - serverRead(this); - - /** - * do some other processing - * @TODO: actually this will hard assume that our stream reader - * is a http parser and it has its queue...think about more - * generalizing here. - */ - { - int i; - - for (i=1; infds; i++) { - int j; - HttpRequestQueue queue = - ((HttpRequestParser)(this->conns)[i].reader)->request_queue; - - for (j=0; jnrequests; j++) { - int k; - HttpRequest request = queue->requests[j]; - - printf("method: %s\n", request->method); - printf("uri: %s\n", request->uri); - printf("version: %s\n", request->http_version); - puts(""); - - for (k=0; k<128; k++) { - if (NULL == (request->header)[k].name) break; - printf("header-name: %s\n", (request->header)[k].name); - printf("header-value: %s\n", (request->header)[k].value); - } + for (i=0; i < events; i++) { + int fd = (this->fds)[i].fd; + //int nreads = 0, nwrites = 0; - delete(&request); + if (0 != ((this->fds)[i].revents & POLLIN)) { + /** + * handle accept + */ + if (this->sock->handle == (this->fds)[i].fd) { + serverHandleAccept(this); } - queue->nrequests = 0; - } - } + /** + * handle reads + */ + else { + serverRead(this, i); + + /** + * do some other processing + * @TODO: actually this will hard assume that our stream reader + * is a http parser and it has its queue...think about more + * generalizing here. + */ + { + int j; + HttpRequestQueue queue = + ((HttpRequestParser)(this->conns)[fd].reader)->request_queue; + + for (j=0; jnrequests; j++) { + HttpRequest request = queue->requests[j]; + + /** + * @TODO: for now simply remove request and send not found. + * Make this sane. + */ + delete(&request); + + /** + * @TODO: the complete response stuff have to be removed here. + */ + time_t t; + struct tm * tmp; + char timestr[200]; + +#define RESP_HEAD "HTTP/1.1 404 Not Found\r\n" \ + "Content-Type: text/html\r\n" \ + "Content-Length: %lu\r\n" \ + "Date: %s\r\n" \ + "Server: testserver\r\n" + +#define RESP_DATA "\n" \ + "\n" \ + "\n" \ + "404 - Not Found" \ + "

404 - Not Found

" \ + "" + + t = time(NULL); + tmp = localtime(&t); + strftime(timestr, sizeof(timestr), "%a, %d %b %Y %T %Z", tmp); + + /** + * @TODO: just to send an answer and be able to make some + * apache benchs i do it here...this definetly MUST BE moved + */ + sprintf((this->conns)[fd].wbuf, RESP_HEAD "\r\n" RESP_DATA, sizeof(RESP_DATA), timestr); + (this->fds)[i].events = (this->fds)[i].events | POLLOUT; + } + + queue->nrequests = 0; + } + } + } - /** - * handle writes - */ + /** + * handle writes + */ + if (0 != ((this->fds)[i].revents & POLLOUT)) { + write( + (this->fds)[i].fd, + (this->conns)[fd].wbuf, + strlen((this->conns)[fd].wbuf)); + (this->fds)[i].events = (this->fds)[i].events & ~POLLOUT; + serverCloseConn(this, i); + } + } } } diff --git a/src/socket.c b/src/socket.c index a744e5e..ac13e1a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -21,7 +21,14 @@ ctor(void * _this, va_list * params) loggerLog(this->log, LOGGER_CRIT, "error opening socket: %s - service terminated", strerror(errno)); - exit(EXIT_FAILURE); + //exit(EXIT_FAILURE); + /** + * @TODO: uhhhh, here we are leaking memory the socket is not + * initialized correctly and no one notices... + * Think about a way to prevent this. + * Well maybe we notice in server.... + */ + return; } /* Make the socket REUSE a TIME_WAIT socket */ diff --git a/src/socket/accept.c b/src/socket/accept.c index 708a45f..928a4f5 100644 --- a/src/socket/accept.c +++ b/src/socket/accept.c @@ -22,7 +22,7 @@ socketAccept(Sock this, char remoteAddr[16]) sock->handle = accept(this->handle, (struct sockaddr *) &(sock->addr), &len); if (-1 == sock->handle) { loggerLog(this->log, LOGGER_WARNING, - "error acception connection: %s", strerror(errno)); + "error accepting connection: %s", strerror(errno)); } else { loggerLog(this->log, LOGGER_INFO, "handling client %s\n", inet_ntoa((sock->addr).sin_addr)); diff --git a/src/testserver.c b/src/testserver.c index 95d5ade..4ce896f 100644 --- a/src/testserver.c +++ b/src/testserver.c @@ -16,6 +16,7 @@ main() Logger logger = new(LoggerStderr, LOGGER_INFO); HttpRequestParser parser = new(HttpRequestParser); Server server = new(Server, logger, parser, 11212, SOMAXCONN); + //Server server = new(Server, logger, parser, 11212, 20); init_signals(); serverRun(server);