Browse Source

changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n)

master
Georg Hopp 14 years ago
parent
commit
bf6a341b4c
  1. 12
      ChangeLog
  2. 2
      include/class.h
  3. 5
      include/http/request.h
  4. 1
      src/http/header/sort.c
  5. 26
      src/http/request.c
  6. 2
      src/http/request/has_keep_alive.c
  7. 36
      src/http/request/header_get.c
  8. 52
      src/http/request/parser/get_header.c
  9. 7
      src/http/request/parser/parse.c
  10. 7
      src/server.c
  11. 5
      src/server/close_conn.c
  12. 4
      src/server/handle_accept.c
  13. 30
      src/server/poll.c
  14. 35
      src/server/run.c
  15. 2
      src/socket.c
  16. 2
      src/testserver.c

12
ChangeLog

@ -1,10 +1,18 @@
2012-02-12 00:05:13 +0100 Georg Hopp
* changed header hashing to use btree (GNU only). @TODO: make this conditional for other systems. Removed the qsort calls on server->fds making O(2nlogn) to O(n) (HEAD, master)
2012-02-11 13:52:32 +0100 Georg Hopp
* daemonize testserver now (origin/master, origin/HEAD)
2012-02-11 12:47:01 +0100 Georg Hopp
* fix seaks and hangs after adding response object (mostly not related with the response object but how i integated it into serverRun (HEAD, master)
* fix seaks and hangs after adding response object (mostly not related with the response object but how i integated it into serverRun
2012-02-10 19:57:57 +0100 Georg Hopp
* started a response handler and changed serverRun to use it for its response (origin/master, origin/HEAD)
* started a response handler and changed serverRun to use it for its response
2012-02-10 12:42:04 +0100 Georg Hopp

2
include/class.h

@ -8,7 +8,9 @@
#include "interface.h"
#ifndef _ISOC99_SOURCE
#define _ISOC99_SOURCE
#endif
#define CLASS_MAGIC 0xFEFE

5
include/http/request.h

@ -9,13 +9,14 @@ CLASS(HttpRequest) {
char * uri;
char * version;
HttpHeader header[128];
int nheader;
HttpHeader header;
char * body;
int nbody;
};
void httpHeaderAdd(HttpHeader *, HttpHeader);
char * XhttpHeaderGet(HttpHeader *, const char *);
char * httpRequestHeaderGet(HttpRequest, const char *);
char httpRequestHasKeepAlive(HttpRequest);

1
src/http/header/sort.c

@ -1,4 +1,5 @@
#include <stdlib.h>
#include <search.h>
#include "http/header.h"

26
src/http/request.c

@ -1,12 +1,19 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <search.h>
#include "class.h"
#include "interface/class.h"
#include "http/request.h"
static
inline
void
_free(void ** data)
{
@ -15,6 +22,14 @@ _free(void ** data)
}
}
static
inline
void
tDelete(void * node)
{
delete(&node);
}
static
void
ctor(void * _this, va_list * params) {}
@ -24,16 +39,17 @@ void
dtor(void * _this)
{
HttpRequest this = _this;
int i;
_free((void **)&(this->version));
_free((void **)&(this->uri));
_free((void **)&(this->method));
for (i=0; i<128; i++) {
if (NULL == (this->header)[i]) break;
delete(&(this->header)[i]);
}
/**
* this is a GNU extension...anyway on most non
* GNUish systems i would not use tsearch anyway
* as the trees will be unbalanced.
*/
tdestroy(this->header, tDelete);
_free((void **)&(this->body));
}

2
src/http/request/has_keep_alive.c

@ -11,7 +11,7 @@ httpRequestHasKeepAlive(HttpRequest request)
char * header;
char * header_ptr;
header = httpHeaderGet(request->header, request->nheader, "connection");
header = XhttpHeaderGet(&(request->header), "connection");
if (NULL == header) {
return 0;

36
src/http/request/header_get.c

@ -3,44 +3,10 @@
#include "http/request.h"
static
inline
unsigned long
sdbm(const unsigned char * str)
{
unsigned long hash = 0;
int c;
while ((c = tolower(*str++)))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
static
inline
int
comp (const void * _a, const void * _b)
{
unsigned long a = *(unsigned long *)_a;
const struct HttpRequestHeader * b = _b;
return (a < b->hash)? -1 : (a > b->hash)? 1 : 0;
}
char *
httpRequestHeaderGet(HttpRequest this, const char * name)
{
unsigned long hash = sdbm((unsigned char *)name);
struct HttpRequestHeader * header;
header = bsearch(
&hash,
this->header,
this->nheader,
sizeof(struct HttpRequestHeader),
comp);
return (NULL != header)? header->value : NULL;
return XhttpHeaderGet(&(this->header), name);
}
// vim: set ts=4 sw=4:

52
src/http/request/parser/get_header.c

@ -1,8 +1,36 @@
#include <search.h>
#include <ctype.h>
#include <stdio.h>
#include "class.h"
#include "interface/class.h"
#include "http/header.h"
#include "http/request.h"
static
inline
unsigned long
sdbm(const unsigned char * str)
{
unsigned long hash = 0;
int c;
while ((c = tolower(*str++)))
hash = c + (hash << 6) + (hash << 16) - hash;
return hash;
}
static
inline
int
comp(const void * _a, const void * _b)
{
HttpHeader a = (HttpHeader)_a;
HttpHeader b = (HttpHeader)_b;
return (a->hash < b->hash)? -1 : (a->hash > b->hash)? 1 : 0;
}
void
httpRequestParserGetHeader(HttpRequest request, char * line)
{
@ -12,7 +40,29 @@ httpRequestParserGetHeader(HttpRequest request, char * line)
*(value++) = 0;
for (; *value == ' ' && *value != 0; value++);
(request->header)[request->nheader++] = new(HttpHeader, name, value);
httpHeaderAdd(&(request->header), new(HttpHeader, name, value));
}
void
httpHeaderAdd(HttpHeader * root, HttpHeader header)
{
HttpHeader * found = tsearch(header, (void **)root, comp);
if (*found != header) {
puts("uhh, duplicate header set. "
"This is not implemented right now. "
"Keep the first one found.");
delete(&header);
}
}
char *
XhttpHeaderGet(HttpHeader * root, const char * name)
{
struct c_HttpHeader search = {sdbm((const unsigned char*)name), NULL, NULL};
HttpHeader * found = tfind(&search, (void **)root, comp);
return (NULL != found)? (*found)->value : NULL;
}
// vim: set ts=4 sw=4:

7
src/http/request/parser/parse.c

@ -82,15 +82,12 @@ httpRequestParserParse(HttpRequestParser this)
break;
case HTTP_REQUEST_HEADERS_DONE:
httpHeaderSort(this->cur_request->header, this->cur_request->nheader);
{
char * nbody;
if (0 == this->cur_request->nbody) {
nbody = httpHeaderGet(
this->cur_request->header,
this->cur_request->nheader,
nbody = XhttpHeaderGet(
&(this->cur_request->header),
"Content-Length");
if (NULL == nbody) {

7
src/server.c

@ -1,6 +1,8 @@
#include <poll.h> /* for select system call and related */
#include <string.h> /* for memset and stuff */
#include <stdlib.h> /* for getopt */
#include <unistd.h>
#include <fcntl.h>
#include "class.h"
#include "server.h"
@ -15,6 +17,7 @@ ctor(void * _this, va_list * params)
Server this = _this;
in_port_t port;
unsigned int backlog;
int flags;
this->logger = va_arg(* params, Logger);
this->reader = va_arg(* params, void*);
@ -22,6 +25,10 @@ ctor(void * _this, va_list * params)
backlog = va_arg(* params, unsigned int);
this->sock = new(Sock, this->logger, port);
flags = fcntl(this->sock->handle, F_GETFL, 0);
fcntl(this->sock->handle, F_SETFL, flags | O_NONBLOCK);
socketListen(this->sock, backlog);
(this->fds)[0].fd = this->sock->handle;

5
src/server/close_conn.c

@ -1,3 +1,4 @@
#include <stdlib.h>
#include <string.h>
#include "server.h"
@ -17,9 +18,7 @@ serverCloseConn(Server this, unsigned int i)
}
(this->conns)[fd].keep_alive = 0;
(this->fds)[i].events = 0;
(this->fds)[i].revents = 0;
(this->fds)[i].fd = 0;
memset(&(this->fds[i]), 0, sizeof(struct pollfd));
}
// vim: set ts=4 sw=4:

4
src/server/handle_accept.c

@ -1,5 +1,5 @@
static
void
int
serverHandleAccept(Server this)
{
char remoteAddr[16] = "";
@ -21,7 +21,7 @@ serverHandleAccept(Server this)
delete(&acc);
}
// (this->fds)[0].revents |= POLLIN;
return (acc)? acc->handle : -1;
}
// vim: set ts=4 sw=4:

30
src/server/poll.c

@ -1,4 +1,5 @@
#define POLLFD(ptr) ((struct pollfd *)(ptr))
#define SWAP(a, b) ((a)^=(b),(b)^=(a),(a)^=(b))
static
inline
@ -25,9 +26,27 @@ int
serverPoll(Server this) {
int events;
qsort(this->fds, this->nfds, sizeof(struct pollfd), sortEvents);
while((this->fds)[this->nfds].fd == 0 && this->nfds > 0) this->nfds--;
this->nfds++;
/**
* put all closed fds to end of array in O(this->nfds)
*/
struct pollfd * fda = &(this->fds[1]);
struct pollfd * fdb = &(this->fds[this->nfds-1]);
while (fda <= fdb) {
while (0 == fdb->fd && fda <= fdb) {
fdb--;
this->nfds--;
}
while (0 != fda->fd && fda <= fdb) fda++;
if (fda < fdb) {
memcpy(fda, fdb, sizeof(struct pollfd));
memset(fdb, 0, sizeof(struct pollfd));
fdb--;
this->nfds--;
}
}
/*
* wait for handles to become ready
@ -45,14 +64,9 @@ serverPoll(Server this) {
loggerLog(this->logger, LOGGER_CRIT,
"poll systemcall failed: [%s] - service terminated",
strerror(errno));
//exit(EXIT_FAILURE); /* @TODO do real shutdown here */
}
}
if (-1 != events) {
qsort(this->fds, this->nfds, sizeof(struct pollfd), sortRevents);
}
return events;
}

35
src/server/run.c

@ -5,6 +5,7 @@
#include <unistd.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include "server.h"
#include "socket.h"
@ -51,22 +52,43 @@ serverRun(Server this)
events = serverPoll(this);
if (doShutdown) break;
for (i=0; i < events; i++) {
for (i=0; i < this->nfds; i++) {
int fd = (this->fds)[i].fd;
//int nreads = 0, nwrites = 0;
int naccs = 10, nreads = 10, nwrites = 10;
if (0 >= events) break;
if (0 != ((this->fds)[i].revents & POLLIN) && 0 < nreads) {
events--;
if (0 != ((this->fds)[i].revents & POLLIN)) {
/**
* handle accept
*/
if (this->sock->handle == (this->fds)[i].fd) {
serverHandleAccept(this);
while(-1 != serverHandleAccept(this) && 0 < naccs) {
naccs--;
switch(errno) {
case EAGAIN:
loggerLog(this->logger,
LOGGER_DEBUG,
"server accept blocks");
break;
default:
loggerLog(this->logger,
LOGGER_DEBUG,
"server accept error");
break;
}
}
}
/**
* handle reads
*/
else {
nreads--;
/**
* do some other processing
* @TODO: actually this will hard assume that our stream reader
@ -126,9 +148,12 @@ serverRun(Server this)
/**
* handle writes
*/
if (0 != ((this->fds)[i].revents & POLLOUT)) {
if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) {
int size;
events--;
nwrites--;
size = write(
(this->fds)[i].fd,
(this->conns)[fd].wbuf,

2
src/socket.c

@ -42,7 +42,7 @@ dtor(void * _this)
{
Sock this = _this;
if (0 != this->handle) {
if (STDERR_FILENO < this->handle) {
shutdown(this->handle, SHUT_RDWR);
close(this->handle);
}

2
src/testserver.c

@ -26,7 +26,7 @@ main()
setrlimit(RLIMIT_CPU, &limit);
init_signals();
daemonize();
//daemonize();
serverRun(server);
delete(&server);

Loading…
Cancel
Save