From 90476e07d827a3bf6d5361a91a9958930fbddf9a Mon Sep 17 00:00:00 2001 From: Georg Hopp Date: Mon, 6 Feb 2012 11:20:00 +0100 Subject: [PATCH] add StreamReader interface, modify HttpRequestParser and Server to use it --- ChangeLog | 54 ++++++++++++++- include/http/request.h | 17 +++-- include/http/request_parser.h | 32 ++++----- include/http/request_queue.h | 6 +- include/interface/stream_reader.h | 19 +++++ include/server.h | 6 +- src/Makefile.am | 5 +- src/http/request_parser.c | 111 ++++++++++++++++++++++-------- src/interface/stream_reader.c | 19 +++++ src/server.c | 2 + src/server/run.c | 28 ++++---- src/testserver.c | 22 ++---- 12 files changed, 233 insertions(+), 88 deletions(-) create mode 100644 include/interface/stream_reader.h create mode 100644 src/interface/stream_reader.c diff --git a/ChangeLog b/ChangeLog index bf0465b..13abc6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,58 @@ +2012-02-06 11:20:00 +0100 Georg Hopp + + * add StreamReader interface, modify HttpRequestParser and Server to use it (HEAD, master) + +2012-02-06 11:15:00 +0100 Georg Hopp + + * add missing include to stdarg.h + +2012-02-06 10:45:33 +0100 Georg Hopp + + * implement clone selector + +2012-02-06 10:43:59 +0100 Georg Hopp + + * add ability to call interface methods with return value + +2012-02-06 02:37:55 +0100 Georg Hopp + + * make build system work again + +2012-02-06 02:37:24 +0100 Georg Hopp + + * remove inline stuff for now ... add carefully again later perhaps + +2012-02-06 00:57:26 +0100 Georg Hopp + + * and also mod conigure.ac + +2012-02-06 00:55:44 +0100 Georg Hopp + + * makefile modification for new class stuff + +2012-02-05 22:55:16 +0100 Georg Hopp + + * changed class tool. Now multiple interface per class are supported as well as simple inheritence. + +2012-02-05 22:47:10 +0100 Georg Hopp + + * some latest work + +2012-02-05 22:44:59 +0100 Georg Hopp + + * added some documentation + +2012-02-05 22:42:37 +0100 Georg Hopp + + * changes related to server code + +2012-01-19 16:41:41 +0100 Georg Hopp + + * added some valueable thought about cclass and how this structure might evolve to a real class + 2012-01-18 07:52:07 +0100 Georg Hopp - * add testserver and did some fixes not shown by my incomplete tests (HEAD, master) + * add testserver and did some fixes not shown by my incomplete tests 2012-01-17 15:40:07 +0100 Georg Hopp diff --git a/include/http/request.h b/include/http/request.h index acbfa97..0a4f83c 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -1,21 +1,20 @@ #ifndef __HTTP_REQUEST_H__ #define __HTTP_REQUEST_H__ -#include "cclass.h" +#include "class.h" -CLASS(HTTP_REQUEST) { - char * http_version; - char * uri; - char * method; +CLASS(HttpRequest) { + char * http_version; + char * uri; + char * method; struct { char * name; char * value; - } header[128]; + } header[128]; - char * body; - - unsigned char done; + char * body; + char done; }; #endif /* __HTTP_REQUEST_H__ */ diff --git a/include/http/request_parser.h b/include/http/request_parser.h index 7d84462..354ca9f 100644 --- a/include/http/request_parser.h +++ b/include/http/request_parser.h @@ -1,32 +1,28 @@ #ifndef __HTTP_REQUEST_PARSER_H__ #define __HTTP_REQUEST_PARSER_H__ -#include "cclass.h" -#include "server.h" -#include "http/request.h" -#include "http/request_queue.h" +#include "class.h" +//#include "http/request.h" +//#include "http/request_queue.h" #define HTTP_REQUEST_PARSER_READ_CHUNK 1024 -#define HTTP_REQUEST_PARSER_START 0 -#define HTTP_REQUEST_PARSER_REQUEST_LINE_DONE 1 -#define HTTP_REQUEST_PARSER_HEADERS_DONE 2 -#define HTTP_REQUEST_PARSER_DONE 3 +typedef enum e_HttpRequestState { + HTTP_REQUEST_START=0, + HTTP_REQUEST_REQEUST_LINE_DONE, + HTTP_REQUEST_HEADERS_DONE, + HTTP_REQUEST_DONE +} HttpRequestState; -CLASS(HTTP_REQUEST_PARSER) { - server_read_hook get_data; +CLASS(HttpRequestParser) { + char * buffer; + size_t buffer_used; - char * buffer; - size_t buffer_used; - - HTTP_REQUEST_QUEUE request_queue; - - unsigned char state; + //HttpRequestQueue request_queue; + HttpRequestState state; }; -void http_request_parser_parse(const char * buffer, size_t size); - #endif /* __HTTP_REQUEST_PARSER_H__ */ // vim: set ts=4 sw=4: diff --git a/include/http/request_queue.h b/include/http/request_queue.h index 7f256da..6654aa0 100644 --- a/include/http/request_queue.h +++ b/include/http/request_queue.h @@ -1,14 +1,14 @@ #ifndef __HTTP_REQUEST_QUEUE_H__ #define __HTTP_REQUEST_QUEUE_H__ -#include "cclass.h" +#include "class.h" #include "http/request.h" #define HTTP_REQUEST_QUEUE_MAX 1024 -CLASS(HTTP_REQUEST_QUEUE) { - REQUEST requests[HTTP_REQUEST_QUEUE_MAX]; +CLASS(HttpRequestQueue) { + HttpRequest requests[HTTP_REQUEST_QUEUE_MAX]; size_t nrequests; } diff --git a/include/interface/stream_reader.h b/include/interface/stream_reader.h new file mode 100644 index 0000000..706d3ae --- /dev/null +++ b/include/interface/stream_reader.h @@ -0,0 +1,19 @@ +#ifndef __STREAM_READER_H__ +#define __STREAM_READER_H__ + +#include + +typedef size_t (* fptr_streamReaderRead)(void *, int fd); + +extern const struct interface i_StreamReader; + +struct i_StreamReader { + const struct interface * const _; + fptr_streamReaderRead read; +}; + +extern size_t streamReaderRead(void *, int fd); + +#endif // __STREAM_READER_H__ + +// vim: set ts=4 sw=4: diff --git a/include/server.h b/include/server.h index a684a33..6e05641 100644 --- a/include/server.h +++ b/include/server.h @@ -26,18 +26,20 @@ typedef void (*server_read_hook)(const char *, size_t); CLASS(Server) { Logger logger; Sock sock; + void * reader; + nfds_t nfds; struct pollfd fds[POLL_FD_NSIZE]; struct { Sock sock; + void * reader; + char * wbuf; char * rbuf; unsigned int rpos; unsigned int wpos; } conns[POLL_FD_NSIZE]; - - server_read_hook read_hook; }; void serverRun(Server this); diff --git a/src/Makefile.am b/src/Makefile.am index b3f75e2..d57e5e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,10 +5,13 @@ CLASS = class.c interface.c interface/class.c SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c SERVER = server.c server/run.c server/close_conn.c LOGGER = logger.c logger/stderr.c logger/syslog.c interface/logger.c +HTTP = interface/stream_reader.c http/request_parser.c AM_CFLAGS = -Wall -I ../include/ bin_PROGRAMS = testserver -testserver_SOURCES = testserver.c $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) signalHandling.c daemonize.c +testserver_SOURCES = testserver.c \ + $(CLASS) $(SOCKET) $(SERVER) $(LOGGER) $(HTTP) \ + signalHandling.c daemonize.c testserver_CFLAGS = -Wall -I ../include/ diff --git a/src/http/request_parser.c b/src/http/request_parser.c index c3c4c08..04f1e92 100644 --- a/src/http/request_parser.c +++ b/src/http/request_parser.c @@ -1,51 +1,108 @@ #include +#include +#include +#include +#include +#include -#include "cclass.h" -#include "http/request.h" +#include "class.h" #include "http/request_parser.h" - - -INIT_CLASS(HTTP_REQUEST_PARSER); - - -__construct(LOGGER) +#include "interface/class.h" +#include "interface/stream_reader.h" +//#include "http/request.h" +//#include "http/request_queue.h" + +static +void +httpRequestParserParse(char * data, size_t * size); + +static +void +ctor(void * _this, va_list * params) { - this->request_queue = va_arg(*params, HTTP_REQUEST_QUEUE); + HttpRequestParser this = _this; + + //this->request_queue = va_arg(*params, HttpRequestQueue); this->buffer = malloc(HTTP_REQUEST_PARSER_READ_CHUNK); } -__destruct(LOGGER) +static +void +dtor(void * _this) { + HttpRequestParser this = _this; + free(this->buffer); } -__jsonConst(LOGGER) {} -__toJson(LOGGER) {} -__clear(LOGGER) {} - - -static void -get_data(HTTP_REQUEST_PARSER this, const char * data, size_t size) +static +void +_clone(void * _this, void * _base) { - size_t remaining, chunks; + HttpRequestParser this = _this; + HttpRequestParser base = _base; + size_t chunks; + + //this->request_queue = base->request_queue; + this->buffer_used = base->buffer_used; - remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK; - chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; + chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; + chunks++; - chunks = (0 == remaining) ? chunks++ : chunks; + this->buffer = malloc(chunks * HTTP_REQUEST_PARSER_READ_CHUNK); + memcpy(this->buffer, base->buffer, this->buffer_used); +} - if (size > remaining) { - this->buffer = - realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK); +static +size_t +get_data(void * _this, int fd) +{ + HttpRequestParser this = _this; + size_t remaining, chunks; + char buffer[1024]; + + size_t size = read(fd, buffer, 1024); + + if (0 < size) { + remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK; + chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK; + + /** + * because a division always rounds down + * chunks holds exactly the currently allocated chunks if + * remaining equals 0 but there is no space left. + * Else chunks holds the actually allocated amount of chunks + * minus 1. + * For this reason chunks always has to be increased by 1. + */ + chunks++; + + if (size > remaining) { + this->buffer = + realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK); + } + + memcpy(this->buffer + this->buffer_used, buffer, size); + this->buffer_used += size; + + httpRequestParserParse(this->buffer, &this->buffer_used); } - memcpy(this->buffer + this->buffer_used, data, size); - this->buffer_used += size; + return size; } -void http_request_parser_parse(const char * data, size_t size) +INIT_IFACE(Class, ctor, dtor, _clone); +INIT_IFACE(StreamReader, get_data); +CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader)); + +static +void +httpRequestParserParse(char * data, size_t * size) { + data[*size] = 0; + printf("%s", data); + *size = 0; } // vim: set ts=4 sw=4: diff --git a/src/interface/stream_reader.c b/src/interface/stream_reader.c new file mode 100644 index 0000000..8bd5e7c --- /dev/null +++ b/src/interface/stream_reader.c @@ -0,0 +1,19 @@ +#include "class.h" +#include "interface/stream_reader.h" + +const struct interface i_StreamReader = { + "streamReader", + 1 +}; + +size_t +streamReaderRead(void * object, int fd) +{ + size_t ret; + + RETCALL(object, StreamReader, read, ret, fd); + + return ret; +} + +// vim: set ts=4 sw=4: diff --git a/src/server.c b/src/server.c index c366b5f..e83c8b8 100644 --- a/src/server.c +++ b/src/server.c @@ -17,6 +17,7 @@ ctor(void * _this, va_list * params) unsigned int backlog; this->logger = va_arg(* params, Logger); + this->reader = va_arg(* params, void*); port = va_arg(* params, int); backlog = va_arg(* params, unsigned int); @@ -40,6 +41,7 @@ dtor(void * _this) * @TODO do some finalization...buffer handling...etc. */ delete(&(this->conns[i]).sock); + delete(&(this->conns[i]).reader); } delete(&this->sock); diff --git a/src/server/run.c b/src/server/run.c index ecac6d7..ae29efd 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -9,6 +9,7 @@ #include "logger.h" #include "signalHandling.h" #include "interface/class.h" +#include "interface/stream_reader.h" #undef MAX #define MAX(x,y) ((x) > (y) ? (x) : (y)) @@ -52,9 +53,10 @@ serverHandleAccept(Server this) acc = socketAccept(this->sock, remoteAddr); if (-1 != acc->handle) { - (this->conns)[this->nfds].sock = acc; // save the socket handle - (this->fds)[this->nfds].fd = acc->handle; - (this->fds)[this->nfds].events = POLLIN; + (this->conns)[this->nfds].sock = acc; // save the socket handle + (this->conns)[this->nfds].reader = clone(this->reader); // clone reader + (this->fds)[this->nfds].fd = acc->handle; + (this->fds)[this->nfds].events = POLLIN; this->nfds++; } else { delete(&acc); @@ -69,32 +71,34 @@ int serverRead(Server this) { unsigned int i; - size_t _read; - char buffer[1024]; for (i=1; infds; i++) { if (0 != ((this->fds)[i].revents & POLLIN)) { - switch (_read = read((this->fds)[i].fd, buffer, 1024)) { + if (NULL == (this->conns)[i].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.... */ - /* FALLTHROUGH */ + /* DROP-THROUGH */ case -1: /* * read failure / close connection - * FALLTHROUGH */ loggerLog(this->logger, LOGGER_INFO, "connection closed..."); serverCloseConn(this, i); break; default: - (this->fds)[i].revents |= POLLIN; - if (NULL != this->read_hook) { - this->read_hook(buffer, _read); - } break; } } diff --git a/src/testserver.c b/src/testserver.c index c290907..95d5ade 100644 --- a/src/testserver.c +++ b/src/testserver.c @@ -4,33 +4,25 @@ #include "server.h" #include "logger.h" -#include "signalHandling.h" -#include "interface/class.h" - -static void -read_hook(const char * _buffer, size_t size) -{ - char buffer[1025]; +#include "http/request_parser.h" - memset(buffer, 0, 1025); - snprintf(buffer, 1025>size? size : 1024, "%s", _buffer); +#include "signalHandling.h" - printf("%s\n", buffer); -} +#include "interface/class.h" int main() { - Logger logger = new(LoggerStderr, LOGGER_INFO); - Server server = new(Server, logger, 11212, SOMAXCONN); - - server->read_hook = read_hook; + Logger logger = new(LoggerStderr, LOGGER_INFO); + HttpRequestParser parser = new(HttpRequestParser); + Server server = new(Server, logger, parser, 11212, SOMAXCONN); init_signals(); serverRun(server); delete(&server); delete(&logger); + delete(&parser); return 0; }