From baa26cd045be80620924ce41ea506bc8b043f8c7 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 13 Jun 2007 01:12:50 +0000 Subject: fixing compile errors --- src/daemon/daemon.c | 28 ++--- src/daemon/internal.h | 171 +++++++++++++++++++++++++++- src/daemon/response.c | 88 +-------------- src/daemon/session.c | 303 ++++++++++++++++++++++++-------------------------- src/daemon/session.h | 97 ---------------- 5 files changed, 326 insertions(+), 361 deletions(-) diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c index e52ac940..0ebf21d0 100644 --- a/src/daemon/daemon.c +++ b/src/daemon/daemon.c @@ -26,16 +26,6 @@ * @version 0.1.0 */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "microhttpd.h" #include "internal.h" #include "response.h" @@ -120,10 +110,10 @@ MHD_unregister_handler(struct MHD_Daemon * daemon, pos = daemon->handlers; prev = NULL; while (pos != NULL) { - if ( (dh == ah->dh) && - (dh_cls == ah->dh_cls) && + if ( (dh == pos->dh) && + (dh_cls == pos->dh_cls) && (0 == strcmp(uri_prefix, - ah->uri_prefix)) ) { + pos->uri_prefix)) ) { if (prev == NULL) daemon->handlers = pos->next; else @@ -160,10 +150,10 @@ MHD_get_fdset(struct MHD_Daemon * daemon, ( (daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) ) return MHD_NO; FD_SET(daemon->socket_fd, - &daemon->read_fd_set); + read_fd_set); if ( (*max_fd) < daemon->socket_fd) *max_fd = daemon->socket_fd; - pos = daemon->session; + pos = daemon->connections; while (pos != NULL) { if (MHD_YES != MHD_session_get_fdset(pos, read_fd_set, @@ -249,7 +239,7 @@ MHD_accept_connection(struct MHD_Daemon * daemon) { strerror(errno)); return MHD_NO; } - if (MHD_NO == daemon->apc(mhd->apc_cls, + if (MHD_NO == daemon->apc(daemon->apc_cls, &addr, addrlen)) { close(s); @@ -485,16 +475,14 @@ MHD_start_daemon(unsigned int options, retVal->port = port; retVal->apc = apc; retVal->apc_cls = apc_cls; - retVal->dh = dh; - retVal->dh_cls = dh_cls; retVal->socket_fd = socket_fd; retVal->default_handler.dh = dh; retVal->default_handler.dh_cls = dh_cls; - retVal->default_henader.uri_prefix = ""; + retVal->default_handler.uri_prefix = ""; retVal->default_handler.next = NULL; if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) || (0 != (options & MHD_USE_SELECT_INTERNALLY)) ) && - (0 != pthread_create(&daemon->pid, + (0 != pthread_create(&retVal->pid, NULL, &MHD_select_thread, daemon)) ) { diff --git a/src/daemon/internal.h b/src/daemon/internal.h index 2f7fd194..61653d8e 100644 --- a/src/daemon/internal.h +++ b/src/daemon/internal.h @@ -35,7 +35,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -45,7 +46,7 @@ #define MHD_MAX_BUF_SIZE 2048 - +#define MAX(a,b) ((a)<(b)) ? (b) : (a) /** * Header or cookie in HTTP request or response. @@ -72,6 +73,172 @@ struct MHD_Access_Handler { }; +/** + * Representation of a response. + */ +struct MHD_Response { + + /** + * Headers to send for the response. Initially + * the linked list is created in inverse order; + * the order should be inverted before sending! + */ + struct MHD_HTTP_Header * first_header; + + /** + * Buffer pointing to data that we are supposed + * to send as a response. + */ + char * data; + + /** + * Closure to give to the content reader + * free callback. + */ + void * crc_cls; + + /** + * How do we get more data? NULL if we are + * given all of the data up front. + */ + MHD_ContentReaderCallback crc; + + /** + * NULL if data must not be freed, otherwise + * either user-specified callback or "&free". + */ + MHD_ContentReaderFreeCallback crfc; + + /** + * Mutex to synchronize access to data/size and + * reference counts. + */ + pthread_mutex_t mutex; + + /** + * Reference count for this response. Free + * once the counter hits zero. + */ + unsigned int reference_count; + + /** + * Set to -1 if size is not known. + */ + size_t total_size; + + /** + * Size of data. + */ + size_t data_size; + + /** + * At what offset in the stream is the + * beginning of data located? + */ + size_t data_start; + +}; + + + +struct MHD_Session { + struct MHD_Session * next; + + struct MHD_Daemon * daemon; + + struct MHD_HTTP_Header * headers_received; + + struct MHD_Response * response; + + char * method; + + char * url; + + /** + * Buffer for reading requests. + */ + char * read_buffer; + + /** + * Buffer for writing response. + */ + char * write_buffer; + + /** + * Foreign address (of length addr_len). + */ + struct sockaddr_in * addr; + + /** + * Thread for this session (if we are using + * one thread per connection). + */ + pthread_t pid; + + size_t read_buffer_size; + + size_t readLoc; + + size_t write_buffer_size; + + size_t writeLoc; + + /** + * Current write position in the actual response + * (excluding headers, content only; should be 0 + * while sending headers). + */ + size_t messagePos; + + /** + * Remaining (!) number of bytes in the upload. + * Set to -1 for unknown (connection will close + * to indicate end of upload). + */ + size_t uploadSize; + + /** + * Length of the foreign address. + */ + socklen_t addr_len; + + /** + * Socket for this connection. Set to -1 if + * this connection has died (daemon should clean + * up in that case). + */ + int socket_fd; + + /** + * Have we finished receiving all of the headers yet? + * Set to 1 once we are done processing all of the + * headers. Note that due to pipelining, it is + * possible that the NEXT request is already + * (partially) waiting in the read buffer. + */ + int headersReceived; + + /** + * Have we finished receiving the data from a + * potential file-upload? + */ + int bodyReceived; + + /** + * Have we finished sending all of the headers yet? + */ + int headersSent; + + /** + * HTTP response code. Only valid if response object + * is already set. + */ + unsigned int responseCode; + +}; + + + struct MHD_Daemon { struct MHD_Access_Handler * handlers; diff --git a/src/daemon/response.c b/src/daemon/response.c index a26b003b..1584dbfd 100644 --- a/src/daemon/response.c +++ b/src/daemon/response.c @@ -26,91 +26,11 @@ * @version 0.1.0 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "microhttpd.h" #include "response.h" #include "internal.h" #include "config.h" - -/** - * Representation of a response. - */ -struct MHD_Response { - - /** - * Headers to send for the response. Initially - * the linked list is created in inverse order; - * the order should be inverted before sending! - */ - struct MHD_HTTP_Header * first_header; - - /** - * Buffer pointing to data that we are supposed - * to send as a response. - */ - void * data; - - /** - * Closure to give to the content reader - * free callback. - */ - void * crc_cls; - - /** - * How do we get more data? NULL if we are - * given all of the data up front. - */ - MHD_ContentReaderCallback crc; - - /** - * NULL if data must not be freed, otherwise - * either user-specified callback or "&free". - */ - MHD_ContentReaderFreeCallback crfc; - - /** - * Mutex to synchronize access to data/size and - * reference counts. - */ - pthread_mutex_t mutex; - - /** - * Reference count for this response. Free - * once the counter hits zero. - */ - unsigned int reference_count; - - /** - * Set to -1 if size is not known. - */ - size_t total_size; - - /** - * Size of data. - */ - size_t data_size; - - /** - * At what offset in the stream is the - * beginning of data located? - */ - size_t data_start; - -}; - - - /** * Add a header line to the response. * @@ -134,9 +54,9 @@ MHD_add_response_header(struct MHD_Response * response, (NULL != strstr(content, "\r")) || (NULL != strstr(content, "\n")) ) return MHD_NO; - hdr = malloc(sizeof(MHD_HTTP_Header)); - hdr->header = STRDUP(header); - hdr->value = STRDUP(content); + hdr = malloc(sizeof(struct MHD_HTTP_Header)); + hdr->header = strdup(header); + hdr->value = strdup(content); hdr->kind = MHD_HEADER_KIND; hdr->next = response->first_header; response->first_header = hdr; @@ -188,7 +108,7 @@ MHD_del_response_header(struct MHD_Response * response, */ int MHD_get_response_headers(struct MHD_Response * response, - MHD_KeyValueIterator * iterator, + MHD_KeyValueIterator iterator, void * iterator_cls) { struct MHD_HTTP_Header * pos; int numHeaders = 0; diff --git a/src/daemon/session.c b/src/daemon/session.c index c50af0ba..fa3864ca 100644 --- a/src/daemon/session.c +++ b/src/daemon/session.c @@ -26,17 +26,6 @@ * @version 0.1.0 */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include "microhttpd.h" #include "session.h" #include "response.h" @@ -55,7 +44,7 @@ int MHD_get_session_values(struct MHD_Session * session, enum MHD_ValueKind kind, - MHD_KeyValueIterator * iterator, + MHD_KeyValueIterator iterator, void * iterator_cls) { int ret; struct MHD_HTTP_Header * pos; @@ -95,7 +84,6 @@ MHD_lookup_session_value(struct MHD_Session * session, if (session == NULL) return NULL; - ret = 0; pos = session->headers_received; while (pos != NULL) { if ( (0 != (pos->kind & kind)) && @@ -145,7 +133,8 @@ MHD_session_get_fdset(struct MHD_Session * session, int * max_fd) { /* FIXME: need to be VERY careful here determining when the socket is ready for - reading/writing; plenty of cases to handle! */ + reading/writing; plenty of cases to handle! + (the current code is one big bug) */ FD_SET(session->socket_fd, read_fd_set); FD_SET(session->socket_fd, write_fd_set); if (session->socket_fd > *max_fd) @@ -165,6 +154,7 @@ MHD_session_get_fdset(struct MHD_Session * session, */ static void MHD_parse_URL(struct MHD_Session * session) { +#if 0 char * working; int pos,i; @@ -179,10 +169,10 @@ MHD_parse_URL(struct MHD_Session * session) { pos = 0; session->documentName = session->headers[0]->value+pos; +#endif } - /** * This function is designed to parse the input buffer of a given session. * @@ -195,6 +185,7 @@ MHD_parse_URL(struct MHD_Session * session) { */ static void MHD_parse_session_headers(struct MHD_Session * session) { +#if 0 const char * crlfcrlf = "\r\n\r\n"; const char * crlf = "\r\n"; @@ -249,8 +240,7 @@ MHD_parse_session_headers(struct MHD_Session * session) { session->headers[session->firstFreeHeader++] = newHeader; curTok = strtok_r(NULL, crlf, &saveptr); } - - return numBytes; +#endif } @@ -269,7 +259,7 @@ MHD_find_access_handler(struct MHD_Session * session) { * (multithreaded, external select, internal select) call this function * to handle reads. */ -static int +int MHD_session_handle_read(struct MHD_Session * session) { int bytes_read; void * tmp; @@ -322,8 +312,8 @@ MHD_session_handle_read(struct MHD_Session * session) { return MHD_NO; } /* dh left "processed" bytes in buffer for next time... */ - memmove(session->readBuffer, - &session->readBuffer[session->readLoc - processed], + memmove(session->read_buffer, + &session->read_buffer[session->readLoc - processed], processed); session->readLoc = processed; session->uploadSize -= processed; @@ -332,157 +322,154 @@ MHD_session_handle_read(struct MHD_Session * session) { return MHD_YES; } +/** + * Allocate the session's write buffer and + * fill it with all of the headers from the + * HTTPd's response. + */ +static void +MHD_build_header_response(struct MHD_Session * session) { + size_t size; + size_t off; + struct MHD_HTTP_Header * pos; + char code[32]; + char * data; + + sprintf(code, + "HTTP/1.1 %u\r\n", + session->responseCode); + off = strlen(code); + /* estimate size */ + size = off + 2; /* extra \r\n at the end */ + pos = session->response->first_header; + while (pos != NULL) { + size += strlen(pos->header) + strlen(pos->value) + 4; /* colon, space, linefeeds */ + pos = pos->next; + } + /* produce data */ + data = malloc(size); + memcpy(data, + code, + off); + pos = session->response->first_header; + while (pos != NULL) { + sprintf(&data[off], + "%s: %s\r\n", + pos->header, + pos->value); + off += strlen(pos->header) + strlen(pos->value) + 4; + pos = pos->next; + } + if (off != size) + abort(); + session->write_buffer = data; + session->write_buffer_size = size; +} /** - * This function was created to handle writes to sockets when it has been - * determined that the socket can be written to. If there is no data - * to be written, however, the function call does nothing. All implementations - * (multithreaded, external select, internal select) call this function + * This function was created to handle writes to sockets when it has + * been determined that the socket can be written to. All + * implementations (multithreaded, external select, internal select) + * call this function */ int MHD_session_handle_write(struct MHD_Session * session) { struct MHD_Response * response; - int i; - char * buffer[2048]; - char * responseMessage; - int numBytesInMessage; + int ret; response = session->response; if(response == NULL) { /* FIXME: LOG: why are we here? */ return MHD_NO; } - numBytesInMessage = 25; - responseMessage = malloc(25); - - pthread_mutex_lock(&response->mutex); - - if(!response->headersSent) { - sprintf(responseMessage, "HTTP/1.1 %i Go to hell!\r\n", response->responseCode); - fprintf(stderr, "%s\n", responseMessage); - if(send(session->socket_fd, responseMessage, strlen(responseMessage), 0) != strlen(responseMessage)) { - fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - - for(i = 0; i < MHD_MAX_HEADERS; i++) { - if(response->headers[i] == NULL) - continue; - - if(strlen(response->headers[i]->header) + strlen(response->headers[i]->value) + 5 > numBytesInMessage) { - free(responseMessage); - responseMessage = malloc(strlen(response->headers[i]->header) + strlen(response->headers[i]->value) + 5); - if(responseMessage == NULL) { - if(daemon->options & MHD_USE_DEBUG) - fprintf(stderr, "Error allocating memory!\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - numBytesInMessage = strlen(response->headers[i]->header) + strlen(response->headers[i]->value) + 5; - } - sprintf(responseMessage, "%s: %s\r\n", response->headers[i]->header, response->headers[i]->value); - fprintf(stderr, "%s\n", responseMessage); - if(send(session->socket_fd, responseMessage, strlen(responseMessage), 0) != strlen(responseMessage)) { - fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - } - - response->headersSent = 1; - } - - if(response->data != NULL) { - if(response->bytesSentSoFar == 0) { - if(numBytesInMessage < 32) { - free(responseMessage); - responseMessage = malloc(32); - if(responseMessage == NULL) { - if(daemon->options & MHD_USE_DEBUG) - fprintf(stderr, "Error allocating memory!\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - } - sprintf(responseMessage, "Content-length: %llu\r\n\r\n", (unsigned long long)response->size); - fprintf(stderr, "%s\n", responseMessage); - if(send(session->socket_fd, responseMessage, strlen(responseMessage),0)!= strlen(responseMessage)) { - fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - } - - i = send(session->socket_fd, response->data+response->bytesSentSoFar, response->size-response->bytesSentSoFar,0); - response->bytesSentSoFar += i; - - fprintf(stderr, "Sent %i bytes of data\nTotal to send is %llu bytes\n", i, (unsigned long long)response->size); - - if(response->bytesSentSoFar == response->size) { - session->currentResponses[session->currentResponse] = NULL; - session->currentResponse = (session->currentResponse + 1) % MHD_MAX_RESPONSE; - response->currentSession = NULL; - - if(response->freeWhenFinished) { - pthread_mutex_unlock(&response->mutex); - MHD_destroy_response(response); - } - /*THIS NEEDS TO BE HANDLED ANOTHER WAY!!! TIMEOUT, ect..., as of now this is the only way to get test case to work - * since client never disconnects on their own! - */ - if(session->currentResponses[session->currentResponse] == NULL) { - MHD_destroy_session(session); - daemon->connections[connection_id] = NULL; - return MHD_NO; - } - } - } else { - if(response->crc == NULL) { - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - - if(response->bytesSentSoFar == 0) { - if(send(session->socket_fd, "\r\n", response->size,0) != 2) { - fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n"); - pthread_mutex_unlock(&response->mutex); - return MHD_NO; - } - } - memset(buffer, 0, 2048); - - i = response->crc(response->crc_cls, response->bytesSentSoFar, (char *)buffer, 2048); - - if(i == -1) { - pthread_mutex_unlock(&response->mutex); - - session->currentResponses[session->currentResponse] = NULL; - session->currentResponse = (session->currentResponse + 1) % MHD_MAX_RESPONSE; - response->currentSession = NULL; - - if(response->freeWhenFinished) { - pthread_mutex_unlock(&response->mutex); - MHD_destroy_response(response); - } - /*THIS NEEDS TO BE HANDLED ANOTHER WAY!!! TIMEOUT, ect..., as of now this is the only way to get test case to work - * since client never disconnects on their own! - */ - if(session->currentResponses[session->currentResponse] == NULL) { - MHD_destroy_session(session); - daemon->connections[connection_id] = NULL; - return MHD_NO; - } - - } else { - i = send(session->socket_fd, buffer, i,0); - response->bytesSentSoFar += i; - } - } - pthread_mutex_unlock(&response->mutex); - return MHD_YES; + if (! session->headersSent) { + if (session->write_buffer == NULL) + MHD_build_header_response(session); + ret = send(session->socket_fd, + &session->write_buffer[session->writeLoc], + session->write_buffer_size - session->writeLoc, + 0); + if (ret < 0) { + if (errno == EINTR) + return MHD_YES; + /* FIXME: log error */ + close(session->socket_fd); + session->socket_fd = -1; + return MHD_NO; + } + session->writeLoc += ret; + if (session->writeLoc == session->write_buffer_size) { + session->writeLoc = 0; + free(session->write_buffer); + session->write_buffer = NULL; + session->write_buffer_size = 0; + session->headersSent = 1; + } + return MHD_YES; + } + if (response->total_size <= session->messagePos) + abort(); /* internal error */ + if (response->crc != NULL) + pthread_mutex_lock(&response->mutex); + + /* prepare send buffer */ + if ( (response->data == NULL) || + (response->data_start > session->messagePos) || + (response->data_start + response->data_size < session->messagePos) ) { + if (response->data_size == 0) { + if (response->data != NULL) + free(response->data); + response->data = malloc(MHD_MAX_BUF_SIZE); + response->data_size = MHD_MAX_BUF_SIZE; + } + ret = response->crc(response->crc_cls, + session->messagePos, + response->data, + MAX(MHD_MAX_BUF_SIZE, + response->data_size - session->messagePos)); + if (ret == -1) { + /* end of message, signal other side by closing! */ + response->data_size = session->messagePos; + close(session->socket_fd); + session->socket_fd = -1; + return MHD_YES; + } + response->data_start = session->messagePos; + response->data_size = ret; + if (ret == 0) + return MHD_YES; /* or NO? */ + } + + /* transmit */ + ret = send(session->socket_fd, + &response->data[session->messagePos - response->data_start], + response->data_size - (session->messagePos - response->data_start), + 0); + if (response->crc != NULL) + pthread_mutex_unlock(&response->mutex); + if (ret == -1) { + if (errno == EINTR) + return MHD_YES; + /* FIXME: log */ + return MHD_NO; + } + session->messagePos += ret; + if (session->messagePos == response->data_size) { + /* reset session, wait for next request! */ + MHD_destroy_response(response); + session->responseCode = 0; + session->response = NULL; + session->headersReceived = 0; + session->headersSent = 0; + session->bodyReceived = 0; + session->messagePos = 0; + free(session->write_buffer); + session->write_buffer = NULL; + session->write_buffer_size = 0; + } + return MHD_YES; } - +/* end of session.c */ diff --git a/src/daemon/session.h b/src/daemon/session.h index 24ddd641..0097a398 100644 --- a/src/daemon/session.h +++ b/src/daemon/session.h @@ -30,103 +30,6 @@ #define SESSION_H -struct MHD_Session { - struct MHD_Session * next; - - struct MHD_Daemon * daemon; - - struct MHD_HTTP_Header * headers_received; - - struct MHD_Response * response; - - char * method; - - char * url; - - /** - * Buffer for reading requests. - */ - void * read_buffer; - - /** - * Buffer for writing response. - */ - void * write_buffer; - - /** - * Foreign address (of length addr_len). - */ - struct sockaddr_in * addr; - - /** - * Thread for this session (if we are using - * one thread per connection). - */ - pthread_t pid; - - size_t read_buffer_size; - - size_t readLoc; - - size_t write_buffer_size; - - size_t writeLoc; - - /** - * Current write position in the actual response - * (excluding headers, content only; should be 0 - * while sending headers). - */ - size_t messagePos; - - /** - * Remaining (!) number of bytes in the upload. - * Set to -1 for unknown (connection will close - * to indicate end of upload). - */ - size_t uploadSize; - - /** - * Length of the foreign address. - */ - socklen_t addr_len; - - /** - * Socket for this connection. Set to -1 if - * this connection has died (daemon should clean - * up in that case). - */ - int socket_fd; - - /** - * Have we finished receiving all of the headers yet? - * Set to 1 once we are done processing all of the - * headers. Note that due to pipelining, it is - * possible that the NEXT request is already - * (partially) waiting in the read buffer. - */ - int headersReceived; - - /** - * Have we finished receiving the data from a - * potential file-upload? - */ - int bodyReceived; - - /** - * Have we finished sending all of the headers yet? - */ - int headersSent; - - /** - * HTTP response code. Only valid if response object - * is already set. - */ - unsigned int responseCode; - -}; - - /** * Obtain the select sets for this session. * -- cgit v1.2.3