Return-Path: Delivered-To: apmail-ws-axis-dev-archive@www.apache.org Received: (qmail 51845 invoked from network); 22 Jul 2008 04:38:41 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 22 Jul 2008 04:38:41 -0000 Received: (qmail 69645 invoked by uid 500); 22 Jul 2008 04:38:40 -0000 Delivered-To: apmail-ws-axis-dev-archive@ws.apache.org Received: (qmail 69514 invoked by uid 500); 22 Jul 2008 04:38:39 -0000 Mailing-List: contact axis-cvs-help@ws.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list axis-cvs@ws.apache.org Received: (qmail 69505 invoked by uid 500); 22 Jul 2008 04:38:39 -0000 Delivered-To: apmail-ws-axis2-cvs@ws.apache.org Received: (qmail 69501 invoked by uid 99); 22 Jul 2008 04:38:39 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 21 Jul 2008 21:38:39 -0700 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 22 Jul 2008 04:37:38 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 802882388B01; Mon, 21 Jul 2008 21:36:09 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r678637 [25/46] - in /webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd: ./ autom4te.cache/ cygwin/ doc/ openwrt/ src/ tests/ tests/docroot/ tests/docroot/123/ tests/docroot/www/ tests/docroot/www/dummydir/ tests/docroot/www/expire/ ... Date: Tue, 22 Jul 2008 04:35:46 -0000 To: axis2-cvs@ws.apache.org From: dinesh@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20080722043609.802882388B01@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,1775 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "buffer.h" +#include "server.h" +#include "log.h" +#include "connections.h" +#include "fdevent.h" + +#include "request.h" +#include "response.h" +#include "network.h" +#include "http_chunk.h" +#include "stat_cache.h" +#include "joblist.h" + +#include "plugin.h" + +#include "inet_ntop_cache.h" + +#ifdef USE_OPENSSL +# include +# include +#endif + +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#include "sys-socket.h" + +typedef struct { + PLUGIN_DATA; +} plugin_data; + +static connection *connections_get_new_connection(server *srv) { + connections *conns = srv->conns; + size_t i; + + if (conns->size == 0) { + conns->size = 128; + conns->ptr = NULL; + conns->ptr = malloc(sizeof(*conns->ptr) * conns->size); + for (i = 0; i < conns->size; i++) { + conns->ptr[i] = connection_init(srv); + } + } else if (conns->size == conns->used) { + conns->size += 128; + conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size); + + for (i = conns->used; i < conns->size; i++) { + conns->ptr[i] = connection_init(srv); + } + } + + connection_reset(srv, conns->ptr[conns->used]); +#if 0 + fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__); + for (i = 0; i < conns->used + 1; i++) { + fprintf(stderr, "%d ", conns->ptr[i]->fd); + } + fprintf(stderr, "\n"); +#endif + + conns->ptr[conns->used]->ndx = conns->used; + return conns->ptr[conns->used++]; +} + +static int connection_del(server *srv, connection *con) { + size_t i; + connections *conns = srv->conns; + connection *temp; + + if (con == NULL) return -1; + + if (-1 == con->ndx) return -1; + + i = con->ndx; + + /* not last element */ + + if (i != conns->used - 1) { + temp = conns->ptr[i]; + conns->ptr[i] = conns->ptr[conns->used - 1]; + conns->ptr[conns->used - 1] = temp; + + conns->ptr[i]->ndx = i; + conns->ptr[conns->used - 1]->ndx = -1; + } + + conns->used--; + + con->ndx = -1; +#if 0 + fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used); + for (i = 0; i < conns->used; i++) { + fprintf(stderr, "%d ", conns->ptr[i]->fd); + } + fprintf(stderr, "\n"); +#endif + return 0; +} + +int connection_close(server *srv, connection *con) { +#ifdef USE_OPENSSL + server_socket *srv_sock = con->srv_socket; +#endif + +#ifdef USE_OPENSSL + if (srv_sock->is_ssl) { + if (con->ssl) SSL_free(con->ssl); + con->ssl = NULL; + } +#endif + + fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); + fdevent_unregister(srv->ev, con->fd); +#ifdef __WIN32 + if (closesocket(con->fd)) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "(warning) close:", con->fd, strerror(errno)); + } +#else + if (close(con->fd)) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "(warning) close:", con->fd, strerror(errno)); + } +#endif + + srv->cur_fds--; +#if 0 + log_error_write(srv, __FILE__, __LINE__, "sd", + "closed()", con->fd); +#endif + + connection_del(srv, con); + connection_set_state(srv, con, CON_STATE_CONNECT); + + return 0; +} + +#if 0 +static void dump_packet(const unsigned char *data, size_t len) { + size_t i, j; + + if (len == 0) return; + + for (i = 0; i < len; i++) { + if (i % 16 == 0) fprintf(stderr, " "); + + fprintf(stderr, "%02x ", data[i]); + + if ((i + 1) % 16 == 0) { + fprintf(stderr, " "); + for (j = 0; j <= i % 16; j++) { + unsigned char c; + + if (i-15+j >= len) break; + + c = data[i-15+j]; + + fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.'); + } + + fprintf(stderr, "\n"); + } + } + + if (len % 16 != 0) { + for (j = i % 16; j < 16; j++) { + fprintf(stderr, " "); + } + + fprintf(stderr, " "); + for (j = i & ~0xf; j < len; j++) { + unsigned char c; + + c = data[j]; + fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.'); + } + fprintf(stderr, "\n"); + } +} +#endif + +static int connection_handle_read_ssl(server *srv, connection *con) { +#ifdef USE_OPENSSL + int r, ssl_err, len; + buffer *b = NULL; + + if (!con->conf.is_ssl) return -1; + + /* don't resize the buffer if we were in SSL_ERROR_WANT_* */ + + do { + if (!con->ssl_error_want_reuse_buffer) { + b = buffer_init(); + buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */ + + /* overwrite everything with 0 */ + memset(b->ptr, 0, b->size); + } else { + b = con->ssl_error_want_reuse_buffer; + } + + len = SSL_read(con->ssl, b->ptr, b->size - 1); + con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */ + + if (len > 0) { + b->used = len; + b->ptr[b->used++] = '\0'; + + /* we move the buffer to the chunk-queue, no need to free it */ + + chunkqueue_append_buffer_weak(con->read_queue, b); + con->bytes_read += len; + b = NULL; + } + } while (len > 0); + + + if (len < 0) { + switch ((r = SSL_get_error(con->ssl, len))) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + con->is_readable = 0; + con->ssl_error_want_reuse_buffer = b; + + b = NULL; + + /* we have to steal the buffer from the queue-queue */ + return 0; + case SSL_ERROR_SYSCALL: + /** + * man SSL_get_error() + * + * SSL_ERROR_SYSCALL + * Some I/O error occurred. The OpenSSL error queue may contain more + * information on the error. If the error queue is empty (i.e. + * ERR_get_error() returns 0), ret can be used to find out more about + * the error: If ret == 0, an EOF was observed that violates the + * protocol. If ret == -1, the underlying BIO reported an I/O error + * (for socket I/O on Unix systems, consult errno for details). + * + */ + while((ssl_err = ERR_get_error())) { + /* get all errors from the error-queue */ + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + r, ERR_error_string(ssl_err, NULL)); + } + + switch(errno) { + default: + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", + len, r, errno, + strerror(errno)); + break; + } + + break; + case SSL_ERROR_ZERO_RETURN: + /* clean shutdown on the remote side */ + + if (r == 0) { + /* FIXME: later */ + } + + /* fall thourgh */ + default: + while((ssl_err = ERR_get_error())) { + /* get all errors from the error-queue */ + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + r, ERR_error_string(ssl_err, NULL)); + } + break; + } + + connection_set_state(srv, con, CON_STATE_ERROR); + + buffer_free(b); + + return -1; + } else if (len == 0) { + con->is_readable = 0; + /* the other end close the connection -> KEEP-ALIVE */ + + /* pipelining */ + buffer_free(b); + + return -2; + } + + return 0; +#else + return -1; +#endif +} + +static int connection_handle_read(server *srv, connection *con) { + int len; + buffer *b; + int toread; + + if (con->conf.is_ssl) { + return connection_handle_read_ssl(srv, con); + } + +#if defined(__WIN32) + b = chunkqueue_get_append_buffer(con->read_queue); + buffer_prepare_copy(b, 4 * 1024); + len = recv(con->fd, b->ptr, b->size - 1, 0); +#else + if (ioctl(con->fd, FIONREAD, &toread)) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "unexpected end-of-file:", + con->fd); + return -1; + } + b = chunkqueue_get_append_buffer(con->read_queue); + buffer_prepare_copy(b, toread + 1); + + len = read(con->fd, b->ptr, b->size - 1); +#endif + + if (len < 0) { + con->is_readable = 0; + + if (errno == EAGAIN) return 0; + if (errno == EINTR) { + /* we have been interrupted before we could read */ + con->is_readable = 1; + return 0; + } + + if (errno != ECONNRESET) { + /* expected for keep-alive */ + log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno); + } + + connection_set_state(srv, con, CON_STATE_ERROR); + + return -1; + } else if (len == 0) { + con->is_readable = 0; + /* the other end close the connection -> KEEP-ALIVE */ + + /* pipelining */ + + return -2; + } else if ((size_t)len < b->size - 1) { + /* we got less then expected, wait for the next fd-event */ + + con->is_readable = 0; + } + + b->used = len; + b->ptr[b->used++] = '\0'; + + con->bytes_read += len; +#if 0 + dump_packet(b->ptr, len); +#endif + + return 0; +} + +static int connection_handle_write_prepare(server *srv, connection *con) { + if (con->mode == DIRECT) { + /* static files */ + switch(con->request.http_method) { + case HTTP_METHOD_GET: + case HTTP_METHOD_POST: + case HTTP_METHOD_HEAD: + case HTTP_METHOD_PUT: + case HTTP_METHOD_MKCOL: + case HTTP_METHOD_DELETE: + case HTTP_METHOD_COPY: + case HTTP_METHOD_MOVE: + case HTTP_METHOD_PROPFIND: + case HTTP_METHOD_PROPPATCH: + case HTTP_METHOD_LOCK: + case HTTP_METHOD_UNLOCK: + break; + case HTTP_METHOD_OPTIONS: + /* + * 400 is coming from the request-parser BEFORE uri.path is set + * 403 is from the response handler when noone else catched it + * + * */ + if ((!con->http_status || con->http_status == 200) && con->uri.path->used && + con->uri.path->ptr[0] != '*') { + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); + + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; + + con->http_status = 200; + con->file_finished = 1; + + chunkqueue_reset(con->write_queue); + } + break; + default: + switch(con->http_status) { + case 400: /* bad request */ + case 414: /* overload request header */ + case 505: /* unknown protocol */ + case 207: /* this was webdav */ + break; + default: + con->http_status = 501; + break; + } + break; + } + } + + if (con->http_status == 0) { + con->http_status = 403; + } + + switch(con->http_status) { + case 400: /* class: header + custom body */ + case 401: + case 403: + case 404: + case 408: + case 409: + case 411: + case 416: + case 423: + case 500: + case 501: + case 503: + case 505: + if (con->mode != DIRECT) break; + + con->file_finished = 0; + + buffer_reset(con->physical.path); + + /* try to send static errorfile */ + if (!buffer_is_empty(con->conf.errorfile_prefix)) { + stat_cache_entry *sce = NULL; + + buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix); + buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status)); + + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { + con->file_finished = 1; + + http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size); + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); + } + } + + if (!con->file_finished) { + buffer *b; + + buffer_reset(con->physical.path); + + con->file_finished = 1; + b = chunkqueue_get_append_buffer(con->write_queue); + + /* build default error-page */ + buffer_copy_string(b, + "\n" + "\n" + "\n" + " \n" + " "); + buffer_append_long(b, con->http_status); + buffer_append_string(b, " - "); + buffer_append_string(b, get_http_status_name(con->http_status)); + + buffer_append_string(b, + "\n" + " \n" + " \n" + "

"); + buffer_append_long(b, con->http_status); + buffer_append_string(b, " - "); + buffer_append_string(b, get_http_status_name(con->http_status)); + + buffer_append_string(b,"

\n" + " \n" + "\n" + ); + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + } + /* fall through */ + case 207: + case 200: /* class: header + body */ + case 201: + case 300: + case 301: + case 302: + case 303: + case 307: + break; + + case 206: /* write_queue is already prepared */ + break; + case 204: + case 205: /* class: header only */ + case 304: + default: + /* disable chunked encoding again as we have no body */ + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; + chunkqueue_reset(con->write_queue); + + con->file_finished = 1; + break; + } + + if (con->file_finished) { + /* we have all the content and chunked encoding is not used, set a content-length */ + + if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && + (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) { + off_t qlen = chunkqueue_length(con->write_queue); + + /** + * The Content-Length header only can be sent if we have content: + * - HEAD doesn't have a content-body (but have a content-length) + * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3) + * + * Otherwise generate a Content-Length header as chunked encoding is not + * available + */ + if ((con->http_status >= 100 && con->http_status < 200) || + con->http_status == 204 || + con->http_status == 304) { + data_string *ds; + /* no Content-Body, no Content-Length */ + if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) { + buffer_reset(ds->value); // Headers with empty values are ignored for output + } + } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) { + /* qlen = 0 is important for Redirects (301, ...) as they MAY have + * a content. Browsers are waiting for a Content otherwise + */ + buffer_copy_off_t(srv->tmp_buf, qlen); + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); + } + } + } else { + /** + * the file isn't finished yet, but we have all headers + * + * to get keep-alive we either need: + * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or + * - Transfer-Encoding: chunked (HTTP/1.1) + */ + + if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) && + ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) { + con->keep_alive = 0; + } + + /** + * if the backend sent a Connection: close, follow the wish + * + * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we + * will close the connection. That's fine. We can always decide the close + * the connection + * + * FIXME: to be nice we should remove the Connection: ... + */ + if (con->parsed_response & HTTP_CONNECTION) { + /* a subrequest disable keep-alive although the client wanted it */ + if (con->keep_alive && !con->response.keep_alive) { + con->keep_alive = 0; + } + } + } + + if (con->request.http_method == HTTP_METHOD_HEAD) { + /** + * a HEAD request has the same as a GET + * without the content + */ + con->file_finished = 1; + + chunkqueue_reset(con->write_queue); + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + } + + http_response_write_header(srv, con); + + return 0; +} + +static int connection_handle_write(server *srv, connection *con) { + switch(network_write_chunkqueue(srv, con, con->write_queue)) { + case 0: + if (con->file_finished) { + connection_set_state(srv, con, CON_STATE_RESPONSE_END); + joblist_append(srv, con); + } + break; + case -1: /* error on our side */ + log_error_write(srv, __FILE__, __LINE__, "sd", + "connection closed: write failed on fd", con->fd); + connection_set_state(srv, con, CON_STATE_ERROR); + joblist_append(srv, con); + break; + case -2: /* remote close */ + connection_set_state(srv, con, CON_STATE_ERROR); + joblist_append(srv, con); + break; + case 1: + con->is_writable = 0; + + /* not finished yet -> WRITE */ + break; + } + + return 0; +} + + + +connection *connection_init(server *srv) { + connection *con; + + UNUSED(srv); + + con = calloc(1, sizeof(*con)); + + con->fd = 0; + con->ndx = -1; + con->fde_ndx = -1; + con->bytes_written = 0; + con->bytes_read = 0; + con->bytes_header = 0; + con->loops_per_request = 0; + +#define CLEAN(x) \ + con->x = buffer_init(); + + CLEAN(request.uri); + CLEAN(request.request_line); + CLEAN(request.request); + CLEAN(request.pathinfo); + + CLEAN(request.orig_uri); + + CLEAN(uri.scheme); + CLEAN(uri.authority); + CLEAN(uri.path); + CLEAN(uri.path_raw); + CLEAN(uri.query); + + CLEAN(physical.doc_root); + CLEAN(physical.path); + CLEAN(physical.basedir); + CLEAN(physical.rel_path); + CLEAN(physical.etag); + CLEAN(parse_request); + + CLEAN(authed_user); + CLEAN(server_name); + CLEAN(error_handler); + CLEAN(dst_addr_buf); + +#undef CLEAN + con->write_queue = chunkqueue_init(); + con->read_queue = chunkqueue_init(); + con->request_content_queue = chunkqueue_init(); + chunkqueue_set_tempdirs(con->request_content_queue, srv->srvconf.upload_tempdirs); + + con->request.headers = array_init(); + con->response.headers = array_init(); + con->environment = array_init(); + + /* init plugin specific connection structures */ + + con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *)); + + con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t)); + config_setup_connection(srv, con); + + return con; +} + +void connections_free(server *srv) { + connections *conns = srv->conns; + size_t i; + + for (i = 0; i < conns->size; i++) { + connection *con = conns->ptr[i]; + + connection_reset(srv, con); + + chunkqueue_free(con->write_queue); + chunkqueue_free(con->read_queue); + chunkqueue_free(con->request_content_queue); + array_free(con->request.headers); + array_free(con->response.headers); + array_free(con->environment); + +#define CLEAN(x) \ + buffer_free(con->x); + + CLEAN(request.uri); + CLEAN(request.request_line); + CLEAN(request.request); + CLEAN(request.pathinfo); + + CLEAN(request.orig_uri); + + CLEAN(uri.scheme); + CLEAN(uri.authority); + CLEAN(uri.path); + CLEAN(uri.path_raw); + CLEAN(uri.query); + + CLEAN(physical.doc_root); + CLEAN(physical.path); + CLEAN(physical.basedir); + CLEAN(physical.etag); + CLEAN(physical.rel_path); + CLEAN(parse_request); + + CLEAN(authed_user); + CLEAN(server_name); + CLEAN(error_handler); + CLEAN(dst_addr_buf); +#undef CLEAN + free(con->plugin_ctx); + free(con->cond_cache); + + free(con); + } + + free(conns->ptr); +} + + +int connection_reset(server *srv, connection *con) { + size_t i; + + plugins_call_connection_reset(srv, con); + + con->is_readable = 1; + con->is_writable = 1; + con->http_status = 0; + con->file_finished = 0; + con->file_started = 0; + con->got_response = 0; + + con->parsed_response = 0; + + con->bytes_written = 0; + con->bytes_written_cur_second = 0; + con->bytes_read = 0; + con->bytes_header = 0; + con->loops_per_request = 0; + + con->request.http_method = HTTP_METHOD_UNSET; + con->request.http_version = HTTP_VERSION_UNSET; + + con->request.http_if_modified_since = NULL; + con->request.http_if_none_match = NULL; + + con->response.keep_alive = 0; + con->response.content_length = -1; + con->response.transfer_encoding = 0; + + con->mode = DIRECT; + +#define CLEAN(x) \ + if (con->x) buffer_reset(con->x); + + CLEAN(request.uri); + CLEAN(request.request_line); + CLEAN(request.pathinfo); + CLEAN(request.request); + + CLEAN(request.orig_uri); + + CLEAN(uri.scheme); + CLEAN(uri.authority); + CLEAN(uri.path); + CLEAN(uri.path_raw); + CLEAN(uri.query); + + CLEAN(physical.doc_root); + CLEAN(physical.path); + CLEAN(physical.basedir); + CLEAN(physical.rel_path); + CLEAN(physical.etag); + + CLEAN(parse_request); + + CLEAN(authed_user); + CLEAN(server_name); + CLEAN(error_handler); +#undef CLEAN + +#define CLEAN(x) \ + if (con->x) con->x->used = 0; + +#undef CLEAN + +#define CLEAN(x) \ + con->request.x = NULL; + + CLEAN(http_host); + CLEAN(http_range); + CLEAN(http_content_type); +#undef CLEAN + con->request.content_length = 0; + + array_reset(con->request.headers); + array_reset(con->response.headers); + array_reset(con->environment); + + chunkqueue_reset(con->write_queue); + chunkqueue_reset(con->request_content_queue); + + /* the plugins should cleanup themself */ + for (i = 0; i < srv->plugins.used; i++) { + plugin *p = ((plugin **)(srv->plugins.ptr))[i]; + plugin_data *pd = p->data; + + if (!pd) continue; + + if (con->plugin_ctx[pd->id] != NULL) { + log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", p->name); + } + + con->plugin_ctx[pd->id] = NULL; + } + + /* The cond_cache gets reset in response.c */ +// config_cond_cache_reset(srv, con); + +#ifdef USE_OPENSSL + if (con->ssl_error_want_reuse_buffer) { + buffer_free(con->ssl_error_want_reuse_buffer); + con->ssl_error_want_reuse_buffer = NULL; + } +#endif + + con->header_len = 0; + con->in_error_handler = 0; + + config_setup_connection(srv, con); + + return 0; +} + +/** + * handle all header and content read + * + * we get called by the state-engine and by the fdevent-handler + */ +int connection_handle_read_state(server *srv, connection *con) { + connection_state_t ostate = con->state; + chunk *c, *last_chunk; + off_t last_offset; + chunkqueue *cq = con->read_queue; + chunkqueue *dst_cq = con->request_content_queue; + int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */ + + if (con->is_readable) { + con->read_idle_ts = srv->cur_ts; + + switch(connection_handle_read(srv, con)) { + case -1: + return -1; + case -2: + is_closed = 1; + break; + default: + break; + } + } + + /* the last chunk might be empty */ + for (c = cq->first; c;) { + if (cq->first == c && c->mem->used == 0) { + /* the first node is empty */ + /* ... and it is empty, move it to unused */ + + cq->first = c->next; + if (cq->first == NULL) cq->last = NULL; + + c->next = cq->unused; + cq->unused = c; + cq->unused_chunks++; + + c = cq->first; + } else if (c->next && c->next->mem->used == 0) { + chunk *fc; + /* next node is the last one */ + /* ... and it is empty, move it to unused */ + + fc = c->next; + c->next = fc->next; + + fc->next = cq->unused; + cq->unused = fc; + cq->unused_chunks++; + + /* the last node was empty */ + if (c->next == NULL) { + cq->last = c; + } + + c = c->next; + } else { + c = c->next; + } + } + + /* we might have got several packets at once + */ + + switch(ostate) { + case CON_STATE_READ: + /* if there is a \r\n\r\n in the chunkqueue + * + * scan the chunk-queue twice + * 1. to find the \r\n\r\n + * 2. to copy the header-packet + * + */ + + last_chunk = NULL; + last_offset = 0; + + for (c = cq->first; !last_chunk && c; c = c->next) { + buffer b; + size_t i; + + b.ptr = c->mem->ptr + c->offset; + b.used = c->mem->used - c->offset; + + for (i = 0; !last_chunk && i < b.used; i++) { + char ch = b.ptr[i]; + size_t have_chars = 0; + + switch (ch) { + case '\r': + /* we have to do a 4 char lookup */ + have_chars = b.used - i - 1; + + if (have_chars >= 4) { + /* all chars are in this buffer */ + + if (0 == strncmp(b.ptr + i, "\r\n\r\n", 4)) { + /* found */ + last_chunk = c; + last_offset = i + 4; + + break; + } + } else { + chunk *lookahead_chunk = c->next; + size_t missing_chars; + /* looks like the following chars are not in the same chunk */ + + missing_chars = 4 - have_chars; + + if (lookahead_chunk && lookahead_chunk->type == MEM_CHUNK) { + /* is the chunk long enough to contain the other chars ? */ + + if (lookahead_chunk->mem->used > missing_chars) { + if (0 == strncmp(b.ptr + i, "\r\n\r\n", have_chars) && + 0 == strncmp(lookahead_chunk->mem->ptr, "\r\n\r\n" + have_chars, missing_chars)) { + + last_chunk = lookahead_chunk; + last_offset = missing_chars; + + break; + } + } else { + /* a splited \r \n */ + break; + } + } + } + + break; + } + } + } + + /* found */ + if (last_chunk) { + buffer_reset(con->request.request); + + for (c = cq->first; c; c = c->next) { + buffer b; + + b.ptr = c->mem->ptr + c->offset; + b.used = c->mem->used - c->offset; + + if (c == last_chunk) { + b.used = last_offset + 1; + } + + buffer_append_string_buffer(con->request.request, &b); + + if (c == last_chunk) { + c->offset += last_offset; + + break; + } else { + /* the whole packet was copied */ + c->offset = c->mem->used - 1; + } + } + + connection_set_state(srv, con, CON_STATE_REQUEST_END); + } else if (chunkqueue_length(cq) > 64 * 1024) { + log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414"); + + con->http_status = 414; /* Request-URI too large */ + con->keep_alive = 0; + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + } + break; + case CON_STATE_READ_POST: + for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) { + off_t weWant, weHave, toRead; + + weWant = con->request.content_length - dst_cq->bytes_in; + + assert(c->mem->used); + + weHave = c->mem->used - c->offset - 1; + + toRead = weHave > weWant ? weWant : weHave; + + /* the new way, copy everything into a chunkqueue whcih might use tempfiles */ + if (con->request.content_length > 64 * 1024) { + chunk *dst_c = NULL; + /* copy everything to max 1Mb sized tempfiles */ + + /* + * if the last chunk is + * - smaller than 1Mb (size < 1Mb) + * - not read yet (offset == 0) + * -> append to it + * otherwise + * -> create a new chunk + * + * */ + + if (dst_cq->last && + dst_cq->last->type == FILE_CHUNK && + dst_cq->last->file.is_temp && + dst_cq->last->offset == 0) { + /* ok, take the last chunk for our job */ + + if (dst_cq->last->file.length < 1 * 1024 * 1024) { + dst_c = dst_cq->last; + + if (dst_c->file.fd == -1) { + /* this should not happen as we cache the fd, but you never know */ + dst_c->file.fd = open(dst_c->file.name->ptr, O_WRONLY | O_APPEND); + } + } else { + /* the chunk is too large now, close it */ + dst_c = dst_cq->last; + + if (dst_c->file.fd != -1) { + close(dst_c->file.fd); + dst_c->file.fd = -1; + } + dst_c = chunkqueue_get_append_tempfile(dst_cq); + } + } else { + dst_c = chunkqueue_get_append_tempfile(dst_cq); + } + + /* we have a chunk, let's write to it */ + + if (dst_c->file.fd == -1) { + /* we don't have file to write to, + * EACCES might be one reason. + * + * Instead of sending 500 we send 413 and say the request is too large + * */ + + log_error_write(srv, __FILE__, __LINE__, "sbs", + "denying upload as opening to temp-file for upload failed:", + dst_c->file.name, strerror(errno)); + + con->http_status = 413; /* Request-Entity too large */ + con->keep_alive = 0; + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + break; + } + + if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) { + /* write failed for some reason ... disk full ? */ + log_error_write(srv, __FILE__, __LINE__, "sbs", + "denying upload as writing to file failed:", + dst_c->file.name, strerror(errno)); + + con->http_status = 413; /* Request-Entity too large */ + con->keep_alive = 0; + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + close(dst_c->file.fd); + dst_c->file.fd = -1; + + break; + } + + dst_c->file.length += toRead; + + if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) { + /* we read everything, close the chunk */ + close(dst_c->file.fd); + dst_c->file.fd = -1; + } + } else { + buffer *b; + + b = chunkqueue_get_append_buffer(dst_cq); + buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead); + } + + c->offset += toRead; + dst_cq->bytes_in += toRead; + } + + /* Content is ready */ + if (dst_cq->bytes_in == (off_t)con->request.content_length) { + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + } + + break; + default: break; + } + + /* the connection got closed and we didn't got enough data to leave one of the READ states + * the only way is to leave here */ + if (is_closed && ostate == con->state) { + connection_set_state(srv, con, CON_STATE_ERROR); + } + + chunkqueue_remove_finished_chunks(cq); + + return 0; +} + +handler_t connection_handle_fdevent(void *s, void *context, int revents) { + server *srv = (server *)s; + connection *con = context; + + joblist_append(srv, con); + + if (revents & FDEVENT_IN) { + con->is_readable = 1; +#if 0 + log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd); +#endif + } + if (revents & FDEVENT_OUT) { + con->is_writable = 1; + /* we don't need the event twice */ + } + + + if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) { + /* looks like an error */ + + /* FIXME: revents = 0x19 still means that we should read from the queue */ + if (revents & FDEVENT_HUP) { + if (con->state == CON_STATE_CLOSE) { + con->close_timeout_ts = 0; + } else { + /* sigio reports the wrong event here + * + * there was no HUP at all + */ +#ifdef USE_LINUX_SIGIO + if (srv->ev->in_sigio == 1) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "connection closed: poll() -> HUP", con->fd); + } else { + connection_set_state(srv, con, CON_STATE_ERROR); + } +#else + connection_set_state(srv, con, CON_STATE_ERROR); +#endif + + } + } else if (revents & FDEVENT_ERR) { +#ifndef USE_LINUX_SIGIO + log_error_write(srv, __FILE__, __LINE__, "sd", + "connection closed: poll() -> ERR", con->fd); +#endif + connection_set_state(srv, con, CON_STATE_ERROR); + } else { + log_error_write(srv, __FILE__, __LINE__, "sd", + "connection closed: poll() -> ???", revents); + } + } + + if (con->state == CON_STATE_READ || + con->state == CON_STATE_READ_POST) { + connection_handle_read_state(srv, con); + } + + if (con->state == CON_STATE_WRITE && + !chunkqueue_is_empty(con->write_queue) && + con->is_writable) { + + if (-1 == connection_handle_write(srv, con)) { + connection_set_state(srv, con, CON_STATE_ERROR); + + log_error_write(srv, __FILE__, __LINE__, "ds", + con->fd, + "handle write failed."); + } else if (con->state == CON_STATE_WRITE) { + con->write_request_ts = srv->cur_ts; + } + } + + if (con->state == CON_STATE_CLOSE) { + /* flush the read buffers */ + int b; + + if (ioctl(con->fd, FIONREAD, &b)) { + log_error_write(srv, __FILE__, __LINE__, "ss", + "ioctl() failed", strerror(errno)); + } + + if (b > 0) { + char buf[1024]; + log_error_write(srv, __FILE__, __LINE__, "sdd", + "CLOSE-read()", con->fd, b); + + /* */ + read(con->fd, buf, sizeof(buf)); + } else { + /* nothing to read */ + + con->close_timeout_ts = 0; + } + } + + return HANDLER_FINISHED; +} + + +connection *connection_accept(server *srv, server_socket *srv_socket) { + /* accept everything */ + + /* search an empty place */ + int cnt; + sock_addr cnt_addr; + socklen_t cnt_len; + /* accept it and register the fd */ + + /** + * check if we can still open a new connections + * + * see #1216 + */ + + if (srv->conns->used >= srv->max_conns) { + return NULL; + } + + cnt_len = sizeof(cnt_addr); + + if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) { + switch (errno) { + case EAGAIN: +#if EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + case EINTR: + /* we were stopped _before_ we had a connection */ + case ECONNABORTED: /* this is a FreeBSD thingy */ + /* we were stopped _after_ we had a connection */ + break; + case EMFILE: + /* out of fds */ + break; + default: + log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno); + } + return NULL; + } else { + connection *con; + + srv->cur_fds++; + + /* ok, we have the connection, register it */ +#if 0 + log_error_write(srv, __FILE__, __LINE__, "sd", + "appected()", cnt); +#endif + srv->con_opened++; + + con = connections_get_new_connection(srv); + + con->fd = cnt; + con->fde_ndx = -1; +#if 0 + gettimeofday(&(con->start_tv), NULL); +#endif + fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con); + + connection_set_state(srv, con, CON_STATE_REQUEST_START); + + con->connection_start = srv->cur_ts; + con->dst_addr = cnt_addr; + buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); + con->srv_socket = srv_socket; + + if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) { + log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); + return NULL; + } +#ifdef USE_OPENSSL + /* connect FD to SSL */ + if (srv_socket->is_ssl) { + if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) { + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + ERR_error_string(ERR_get_error(), NULL)); + + return NULL; + } + + SSL_set_accept_state(con->ssl); + con->conf.is_ssl=1; + + if (1 != (SSL_set_fd(con->ssl, cnt))) { + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + ERR_error_string(ERR_get_error(), NULL)); + return NULL; + } + } +#endif + return con; + } +} + + +int connection_state_machine(server *srv, connection *con) { + int done = 0, r; +#ifdef USE_OPENSSL + server_socket *srv_sock = con->srv_socket; +#endif + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state at start", + con->fd, + connection_get_state(con->state)); + } + + while (done == 0) { + size_t ostate = con->state; + int b; + + switch (con->state) { + case CON_STATE_REQUEST_START: /* transient */ + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + con->request_start = srv->cur_ts; + con->read_idle_ts = srv->cur_ts; + + con->request_count++; + con->loops_per_request = 0; + + connection_set_state(srv, con, CON_STATE_READ); + + /* patch con->conf.is_ssl if the connection is a ssl-socket already */ + +#ifdef USE_OPENSSL + con->conf.is_ssl = srv_sock->is_ssl; +#endif + + break; + case CON_STATE_REQUEST_END: /* transient */ + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + if (http_request_parse(srv, con)) { + /* we have to read some data from the POST request */ + + connection_set_state(srv, con, CON_STATE_READ_POST); + + break; + } + + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + break; + case CON_STATE_HANDLE_REQUEST: + /* + * the request is parsed + * + * decided what to do with the request + * - + * + * + */ + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + switch (r = http_response_prepare(srv, con)) { + case HANDLER_FINISHED: + if (con->mode == DIRECT) { + if (con->http_status == 404 || + con->http_status == 403) { + /* 404 error-handler */ + + if (con->in_error_handler == 0 && + (!buffer_is_empty(con->conf.error_handler) || + !buffer_is_empty(con->error_handler))) { + /* call error-handler */ + + con->error_handler_saved_status = con->http_status; + con->http_status = 0; + + if (buffer_is_empty(con->error_handler)) { + buffer_copy_string_buffer(con->request.uri, con->conf.error_handler); + } else { + buffer_copy_string_buffer(con->request.uri, con->error_handler); + } + buffer_reset(con->physical.path); + + con->in_error_handler = 1; + + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + done = -1; + break; + } else if (con->in_error_handler) { + /* error-handler is a 404 */ + + con->http_status = con->error_handler_saved_status; + } + } else if (con->in_error_handler) { + /* error-handler is back and has generated content */ + /* if Status: was set, take it otherwise use 200 */ + } + } + if (con->http_status == 0) con->http_status = 200; + + /* we have something to send, go on */ + connection_set_state(srv, con, CON_STATE_RESPONSE_START); + break; + case HANDLER_WAIT_FOR_FD: + srv->want_fds++; + + fdwaitqueue_append(srv, con); + + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + break; + case HANDLER_COMEBACK: + done = -1; + case HANDLER_WAIT_FOR_EVENT: + /* come back here */ + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); + + break; + case HANDLER_ERROR: + /* something went wrong */ + connection_set_state(srv, con, CON_STATE_ERROR); + break; + default: + log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r); + break; + } + + break; + case CON_STATE_RESPONSE_START: + /* + * the decision is done + * - create the HTTP-Response-Header + * + */ + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + if (-1 == connection_handle_write_prepare(srv, con)) { + connection_set_state(srv, con, CON_STATE_ERROR); + + break; + } + + connection_set_state(srv, con, CON_STATE_WRITE); + break; + case CON_STATE_RESPONSE_END: /* transient */ + /* log the request */ + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + plugins_call_handle_request_done(srv, con); + + srv->con_written++; + + if (con->keep_alive) { + connection_set_state(srv, con, CON_STATE_REQUEST_START); + +#if 0 + con->request_start = srv->cur_ts; + con->read_idle_ts = srv->cur_ts; +#endif + } else { + switch(r = plugins_call_handle_connection_close(srv, con)) { + case HANDLER_GO_ON: + case HANDLER_FINISHED: + break; + default: + log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); + break; + } + +#ifdef USE_OPENSSL + if (srv_sock->is_ssl) { + switch (SSL_shutdown(con->ssl)) { + case 1: + /* done */ + break; + case 0: + /* wait for fd-event + * + * FIXME: wait for fdevent and call SSL_shutdown again + * + */ + + break; + default: + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + ERR_error_string(ERR_get_error(), NULL)); + } + } +#endif + connection_close(srv, con); + + srv->con_closed++; + } + + connection_reset(srv, con); + + break; + case CON_STATE_CONNECT: + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + chunkqueue_reset(con->read_queue); + + con->request_count = 0; + + break; + case CON_STATE_CLOSE: + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + if (con->keep_alive) { + if (ioctl(con->fd, FIONREAD, &b)) { + log_error_write(srv, __FILE__, __LINE__, "ss", + "ioctl() failed", strerror(errno)); + } + if (b > 0) { + char buf[1024]; + log_error_write(srv, __FILE__, __LINE__, "sdd", + "CLOSE-read()", con->fd, b); + + /* */ + read(con->fd, buf, sizeof(buf)); + } else { + /* nothing to read */ + + con->close_timeout_ts = 0; + } + } else { + con->close_timeout_ts = 0; + } + + if (srv->cur_ts - con->close_timeout_ts > 1) { + connection_close(srv, con); + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "connection closed for fd", con->fd); + } + } + + break; + case CON_STATE_READ_POST: + case CON_STATE_READ: + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + connection_handle_read_state(srv, con); + break; + case CON_STATE_WRITE: + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state for fd", con->fd, connection_get_state(con->state)); + } + + /* only try to write if we have something in the queue */ + if (!chunkqueue_is_empty(con->write_queue)) { +#if 0 + log_error_write(srv, __FILE__, __LINE__, "dsd", + con->fd, + "packets to write:", + con->write_queue->used); +#endif + } + if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) { + if (-1 == connection_handle_write(srv, con)) { + log_error_write(srv, __FILE__, __LINE__, "ds", + con->fd, + "handle write failed."); + connection_set_state(srv, con, CON_STATE_ERROR); + } else if (con->state == CON_STATE_WRITE) { + con->write_request_ts = srv->cur_ts; + } + } + + break; + case CON_STATE_ERROR: /* transient */ + + /* even if the connection was drop we still have to write it to the access log */ + if (con->http_status) { + plugins_call_handle_request_done(srv, con); + } +#ifdef USE_OPENSSL + if (srv_sock->is_ssl) { + int ret; + switch ((ret = SSL_shutdown(con->ssl))) { + case 1: + /* ok */ + break; + case 0: + SSL_shutdown(con->ssl); + break; + default: + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + SSL_get_error(con->ssl, ret), + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + } +#endif + + switch(con->mode) { + case DIRECT: +#if 0 + log_error_write(srv, __FILE__, __LINE__, "sd", + "emergency exit: direct", + con->fd); +#endif + break; + default: + switch(r = plugins_call_handle_connection_close(srv, con)) { + case HANDLER_GO_ON: + case HANDLER_FINISHED: + break; + default: + log_error_write(srv, __FILE__, __LINE__, ""); + break; + } + break; + } + + connection_reset(srv, con); + + /* close the connection */ + if ((con->keep_alive == 1) && + (0 == shutdown(con->fd, SHUT_WR))) { + con->close_timeout_ts = srv->cur_ts; + connection_set_state(srv, con, CON_STATE_CLOSE); + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sd", + "shutdown for fd", con->fd); + } + } else { + connection_close(srv, con); + } + + con->keep_alive = 0; + + srv->con_closed++; + + break; + default: + log_error_write(srv, __FILE__, __LINE__, "sdd", + "unknown state:", con->fd, con->state); + + break; + } + + if (done == -1) { + done = 0; + } else if (ostate == con->state) { + done = 1; + } + } + + if (srv->srvconf.log_state_handling) { + log_error_write(srv, __FILE__, __LINE__, "sds", + "state at exit:", + con->fd, + connection_get_state(con->state)); + } + + switch(con->state) { + case CON_STATE_READ_POST: + case CON_STATE_READ: + case CON_STATE_CLOSE: + fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN); + break; + case CON_STATE_WRITE: + /* request write-fdevent only if we really need it + * - if we have data to write + * - if the socket is not writable yet + */ + if (!chunkqueue_is_empty(con->write_queue) && + (con->is_writable == 0) && + (con->traffic_limit_reached == 0)) { + fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT); + } else { + fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); + } + break; + default: + fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); + break; + } + + return 0; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.h URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.h?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.h (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/connections.h Mon Jul 21 21:35:35 2008 @@ -0,0 +1,19 @@ +#ifndef _CONNECTIONS_H_ +#define _CONNECTIONS_H_ + +#include "server.h" +#include "fdevent.h" + +connection *connection_init(server *srv); +int connection_reset(server *srv, connection *con); +void connections_free(server *srv); + +connection * connection_accept(server *srv, server_socket *srv_sock); +int connection_close(server *srv, connection *con); + +int connection_set_state(server *srv, connection *con, connection_state_t state); +const char * connection_get_state(connection_state_t state); +const char * connection_get_short_state(connection_state_t state); +int connection_state_machine(server *srv, connection *con); + +#endif Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,82 @@ +#include "crc32.h" + +#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF]) + +static const unsigned int crc_c[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, + 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, + 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, + 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, + 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, + 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, + 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, + 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, + 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, + 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, + 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, + 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, + 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, + 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, + 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, + 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, + 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, + 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, + 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, + 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, + 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, + 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, + 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, + 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, + 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, + 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, + 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, + 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, + 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, + 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, + 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, + 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, + 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, + 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, + 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, +}; + + +uint32_t generate_crc32c(char *buffer, size_t length) { + size_t i; + uint32_t crc32 = ~0L; + + for (i = 0; i < length; i++){ + CRC32C(crc32, (unsigned char)buffer[i]); + } + return ~crc32; +} + Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.h URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.h?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.h (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/crc32.h Mon Jul 21 21:35:35 2008 @@ -0,0 +1,18 @@ +#ifndef __crc32cr_table_h__ +#define __crc32cr_table_h__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#if defined HAVE_STDINT_H +#include +#elif defined HAVE_INTTYPES_H +#include +#endif + +uint32_t generate_crc32c(char *string, size_t length); + +#endif Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_array.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_array.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_array.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_array.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "array.h" + +static data_unset *data_array_copy(const data_unset *s) { + data_array *src = (data_array *)s; + data_array *ds = data_array_init(); + + buffer_copy_string_buffer(ds->key, src->key); + array_free(ds->value); + ds->value = array_init_array(src->value); + ds->is_index_key = src->is_index_key; + return (data_unset *)ds; +} + +static void data_array_free(data_unset *d) { + data_array *ds = (data_array *)d; + + buffer_free(ds->key); + array_free(ds->value); + + free(d); +} + +static void data_array_reset(data_unset *d) { + data_array *ds = (data_array *)d; + + /* reused array elements */ + buffer_reset(ds->key); + array_reset(ds->value); +} + +static int data_array_insert_dup(data_unset *dst, data_unset *src) { + UNUSED(dst); + + src->free(src); + + return 0; +} + +static void data_array_print(const data_unset *d, int depth) { + data_array *ds = (data_array *)d; + + array_print(ds->value, depth); +} + +data_array *data_array_init(void) { + data_array *ds; + + ds = calloc(1, sizeof(*ds)); + + ds->key = buffer_init(); + ds->value = array_init(); + + ds->copy = data_array_copy; + ds->free = data_array_free; + ds->reset = data_array_reset; + ds->insert_dup = data_array_insert_dup; + ds->print = data_array_print; + ds->type = TYPE_ARRAY; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_config.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_config.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_config.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_config.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,138 @@ +#include +#include +#include + +#include "array.h" + +static data_unset *data_config_copy(const data_unset *s) { + data_config *src = (data_config *)s; + data_config *ds = data_config_init(); + + buffer_copy_string_buffer(ds->key, src->key); + buffer_copy_string_buffer(ds->comp_key, src->comp_key); + array_free(ds->value); + ds->value = array_init_array(src->value); + return (data_unset *)ds; +} + +static void data_config_free(data_unset *d) { + data_config *ds = (data_config *)d; + + buffer_free(ds->key); + buffer_free(ds->op); + buffer_free(ds->comp_key); + + array_free(ds->value); + array_free(ds->childs); + + if (ds->string) buffer_free(ds->string); +#ifdef HAVE_PCRE_H + if (ds->regex) pcre_free(ds->regex); + if (ds->regex_study) pcre_free(ds->regex_study); +#endif + + free(d); +} + +static void data_config_reset(data_unset *d) { + data_config *ds = (data_config *)d; + + /* reused array elements */ + buffer_reset(ds->key); + buffer_reset(ds->comp_key); + array_reset(ds->value); +} + +static int data_config_insert_dup(data_unset *dst, data_unset *src) { + UNUSED(dst); + + src->free(src); + + return 0; +} + +static void data_config_print(const data_unset *d, int depth) { + data_config *ds = (data_config *)d; + array *a = (array *)ds->value; + size_t i; + size_t maxlen; + + if (0 == ds->context_ndx) { + fprintf(stdout, "config {\n"); + } + else { + fprintf(stdout, "$%s %s \"%s\" {\n", + ds->comp_key->ptr, ds->op->ptr, ds->string->ptr); + array_print_indent(depth + 1); + fprintf(stdout, "# block %d\n", ds->context_ndx); + } + depth ++; + + maxlen = array_get_max_key_length(a); + for (i = 0; i < a->used; i ++) { + data_unset *du = a->data[i]; + size_t len = strlen(du->key->ptr); + size_t j; + + array_print_indent(depth); + fprintf(stdout, "%s", du->key->ptr); + for (j = maxlen - len; j > 0; j --) { + fprintf(stdout, " "); + } + fprintf(stdout, " = "); + du->print(du, depth); + fprintf(stdout, "\n"); + } + + if (ds->childs) { + fprintf(stdout, "\n"); + for (i = 0; i < ds->childs->used; i ++) { + data_unset *du = ds->childs->data[i]; + + /* only the 1st block of chaining */ + if (NULL == ((data_config *)du)->prev) { + fprintf(stdout, "\n"); + array_print_indent(depth); + du->print(du, depth); + fprintf(stdout, "\n"); + } + } + } + + depth --; + array_print_indent(depth); + fprintf(stdout, "}"); + if (0 != ds->context_ndx) { + fprintf(stdout, " # end of $%s %s \"%s\"", + ds->comp_key->ptr, ds->op->ptr, ds->string->ptr); + } + + if (ds->next) { + fprintf(stdout, "\n"); + array_print_indent(depth); + fprintf(stdout, "else "); + ds->next->print((data_unset *)ds->next, depth); + } +} + +data_config *data_config_init(void) { + data_config *ds; + + ds = calloc(1, sizeof(*ds)); + + ds->key = buffer_init(); + ds->op = buffer_init(); + ds->comp_key = buffer_init(); + ds->value = array_init(); + ds->childs = array_init(); + ds->childs->is_weakref = 1; + + ds->copy = data_config_copy; + ds->free = data_config_free; + ds->reset = data_config_reset; + ds->insert_dup = data_config_insert_dup; + ds->print = data_config_print; + ds->type = TYPE_CONFIG; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_count.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_count.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_count.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_count.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,68 @@ +#include +#include +#include + +#include "array.h" + +static data_unset *data_count_copy(const data_unset *s) { + data_count *src = (data_count *)s; + data_count *ds = data_count_init(); + + buffer_copy_string_buffer(ds->key, src->key); + ds->count = src->count; + ds->is_index_key = src->is_index_key; + return (data_unset *)ds; +} + +static void data_count_free(data_unset *d) { + data_count *ds = (data_count *)d; + + buffer_free(ds->key); + + free(d); +} + +static void data_count_reset(data_unset *d) { + data_count *ds = (data_count *)d; + + buffer_reset(ds->key); + + ds->count = 0; +} + +static int data_count_insert_dup(data_unset *dst, data_unset *src) { + data_count *ds_dst = (data_count *)dst; + data_count *ds_src = (data_count *)src; + + ds_dst->count += ds_src->count; + + src->free(src); + + return 0; +} + +static void data_count_print(const data_unset *d, int depth) { + data_count *ds = (data_count *)d; + UNUSED(depth); + + fprintf(stdout, "count(%d)", ds->count); +} + + +data_count *data_count_init(void) { + data_count *ds; + + ds = calloc(1, sizeof(*ds)); + + ds->key = buffer_init(); + ds->count = 1; + + ds->copy = data_count_copy; + ds->free = data_count_free; + ds->reset = data_count_reset; + ds->insert_dup = data_count_insert_dup; + ds->print = data_count_print; + ds->type = TYPE_COUNT; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_fastcgi.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_fastcgi.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_fastcgi.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_fastcgi.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,69 @@ +#include +#include +#include + +#include "array.h" +#include "fastcgi.h" + +static data_unset *data_fastcgi_copy(const data_unset *s) { + data_fastcgi *src = (data_fastcgi *)s; + data_fastcgi *ds = data_fastcgi_init(); + + buffer_copy_string_buffer(ds->key, src->key); + buffer_copy_string_buffer(ds->host, src->host); + ds->is_index_key = src->is_index_key; + return (data_unset *)ds; +} + +static void data_fastcgi_free(data_unset *d) { + data_fastcgi *ds = (data_fastcgi *)d; + + buffer_free(ds->key); + buffer_free(ds->host); + + free(d); +} + +static void data_fastcgi_reset(data_unset *d) { + data_fastcgi *ds = (data_fastcgi *)d; + + buffer_reset(ds->key); + buffer_reset(ds->host); + +} + +static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) { + UNUSED(dst); + + src->free(src); + + return 0; +} + +static void data_fastcgi_print(const data_unset *d, int depth) { + data_fastcgi *ds = (data_fastcgi *)d; + UNUSED(depth); + + fprintf(stdout, "fastcgi(%s)", ds->host->ptr); +} + + +data_fastcgi *data_fastcgi_init(void) { + data_fastcgi *ds; + + ds = calloc(1, sizeof(*ds)); + + ds->key = buffer_init(); + ds->host = buffer_init(); + ds->port = 0; + ds->is_disabled = 0; + + ds->copy = data_fastcgi_copy; + ds->free = data_fastcgi_free; + ds->reset = data_fastcgi_reset; + ds->insert_dup = data_fastcgi_insert_dup; + ds->print = data_fastcgi_print; + ds->type = TYPE_FASTCGI; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_integer.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_integer.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_integer.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_integer.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "array.h" + +static data_unset *data_integer_copy(const data_unset *s) { + data_integer *src = (data_integer *)s; + data_integer *ds = data_integer_init(); + + buffer_copy_string_buffer(ds->key, src->key); + ds->is_index_key = src->is_index_key; + ds->value = src->value; + return (data_unset *)ds; +} + +static void data_integer_free(data_unset *d) { + data_integer *ds = (data_integer *)d; + + buffer_free(ds->key); + + free(d); +} + +static void data_integer_reset(data_unset *d) { + data_integer *ds = (data_integer *)d; + + /* reused integer elements */ + buffer_reset(ds->key); + ds->value = 0; +} + +static int data_integer_insert_dup(data_unset *dst, data_unset *src) { + UNUSED(dst); + + src->free(src); + + return 0; +} + +static void data_integer_print(const data_unset *d, int depth) { + data_integer *ds = (data_integer *)d; + UNUSED(depth); + + fprintf(stdout, "%d", ds->value); +} + + +data_integer *data_integer_init(void) { + data_integer *ds; + + ds = calloc(1, sizeof(*ds)); + + ds->key = buffer_init(); + ds->value = 0; + + ds->copy = data_integer_copy; + ds->free = data_integer_free; + ds->reset = data_integer_reset; + ds->insert_dup = data_integer_insert_dup; + ds->print = data_integer_print; + ds->type = TYPE_INTEGER; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_string.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_string.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_string.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/data_string.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,104 @@ +#include +#include +#include +#include + +#include "array.h" + +static data_unset *data_string_copy(const data_unset *s) { + data_string *src = (data_string *)s; + data_string *ds = data_string_init(); + + buffer_copy_string_buffer(ds->key, src->key); + buffer_copy_string_buffer(ds->value, src->value); + ds->is_index_key = src->is_index_key; + return (data_unset *)ds; +} + +static void data_string_free(data_unset *d) { + data_string *ds = (data_string *)d; + + buffer_free(ds->key); + buffer_free(ds->value); + + free(d); +} + +static void data_string_reset(data_unset *d) { + data_string *ds = (data_string *)d; + + /* reused array elements */ + buffer_reset(ds->key); + buffer_reset(ds->value); +} + +static int data_string_insert_dup(data_unset *dst, data_unset *src) { + data_string *ds_dst = (data_string *)dst; + data_string *ds_src = (data_string *)src; + + if (ds_dst->value->used) { + buffer_append_string(ds_dst->value, ", "); + buffer_append_string_buffer(ds_dst->value, ds_src->value); + } else { + buffer_copy_string_buffer(ds_dst->value, ds_src->value); + } + + src->free(src); + + return 0; +} + +static int data_response_insert_dup(data_unset *dst, data_unset *src) { + data_string *ds_dst = (data_string *)dst; + data_string *ds_src = (data_string *)src; + + if (ds_dst->value->used) { + buffer_append_string(ds_dst->value, "\r\n"); + buffer_append_string_buffer(ds_dst->value, ds_dst->key); + buffer_append_string(ds_dst->value, ": "); + buffer_append_string_buffer(ds_dst->value, ds_src->value); + } else { + buffer_copy_string_buffer(ds_dst->value, ds_src->value); + } + + src->free(src); + + return 0; +} + + +static void data_string_print(const data_unset *d, int depth) { + data_string *ds = (data_string *)d; + UNUSED(depth); + + fprintf(stdout, "\"%s\"", ds->value->used ? ds->value->ptr : ""); +} + + +data_string *data_string_init(void) { + data_string *ds; + + ds = calloc(1, sizeof(*ds)); + assert(ds); + + ds->key = buffer_init(); + ds->value = buffer_init(); + + ds->copy = data_string_copy; + ds->free = data_string_free; + ds->reset = data_string_reset; + ds->insert_dup = data_string_insert_dup; + ds->print = data_string_print; + ds->type = TYPE_STRING; + + return ds; +} + +data_string *data_response_init(void) { + data_string *ds; + + ds = data_string_init(); + ds->insert_dup = data_response_insert_dup; + + return ds; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,55 @@ +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined HAVE_STDINT_H +#include +#elif defined HAVE_INTTYPES_H +#include +#endif + +#include "buffer.h" +#include "etag.h" + +int etag_is_equal(buffer *etag, const char *matches) { + if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1; + return 0; +} + +int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) { + if (0 == flags) return 0; + + buffer_reset(etag); + + if (flags & ETAG_USE_INODE) { + buffer_append_off_t(etag, st->st_ino); + buffer_append_string_len(etag, CONST_STR_LEN("-")); + } + + if (flags & ETAG_USE_SIZE) { + buffer_append_off_t(etag, st->st_size); + buffer_append_string_len(etag, CONST_STR_LEN("-")); + } + + if (flags & ETAG_USE_MTIME) { + buffer_append_long(etag, st->st_mtime); + } + + return 0; +} + +int etag_mutate(buffer *mut, buffer *etag) { + size_t i; + uint32_t h; + + for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); + + buffer_reset(mut); + buffer_copy_string_len(mut, CONST_STR_LEN("\"")); + buffer_append_long(mut, h); + buffer_append_string_len(mut, CONST_STR_LEN("\"")); + + return 0; +} Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.h URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.h?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.h (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/etag.h Mon Jul 21 21:35:35 2008 @@ -0,0 +1,17 @@ +#ifndef ETAG_H +#define ETAG_H + +#include +#include +#include + +#include "buffer.h" + +typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_flags_t; + +int etag_is_equal(buffer *etag, const char *matches); +int etag_create(buffer *etag, struct stat *st, etag_flags_t flags); +int etag_mutate(buffer *mut, buffer *etag); + + +#endif Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fastcgi.h URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fastcgi.h?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fastcgi.h (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fastcgi.h Mon Jul 21 21:35:35 2008 @@ -0,0 +1,136 @@ +/* + * fastcgi.h -- + * + * Defines for the FastCGI protocol. + * + * + * Copyright (c) 1995-1996 Open Market, Inc. + * + * See the file "LICENSE.TERMS" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * $Id: fastcgi.h,v 1.1.1.1 2003/10/18 09:54:10 weigon Exp $ + */ + +#ifndef _FASTCGI_H +#define _FASTCGI_H + +/* + * Listening socket file number + */ +#define FCGI_LISTENSOCK_FILENO 0 + +typedef struct { + unsigned char version; + unsigned char type; + unsigned char requestIdB1; + unsigned char requestIdB0; + unsigned char contentLengthB1; + unsigned char contentLengthB0; + unsigned char paddingLength; + unsigned char reserved; +} FCGI_Header; + +#define FCGI_MAX_LENGTH 0xffff + +/* + * Number of bytes in a FCGI_Header. Future versions of the protocol + * will not reduce this number. + */ +#define FCGI_HEADER_LEN 8 + +/* + * Value for version component of FCGI_Header + */ +#define FCGI_VERSION_1 1 + +/* + * Values for type component of FCGI_Header + */ +#define FCGI_BEGIN_REQUEST 1 +#define FCGI_ABORT_REQUEST 2 +#define FCGI_END_REQUEST 3 +#define FCGI_PARAMS 4 +#define FCGI_STDIN 5 +#define FCGI_STDOUT 6 +#define FCGI_STDERR 7 +#define FCGI_DATA 8 +#define FCGI_GET_VALUES 9 +#define FCGI_GET_VALUES_RESULT 10 +#define FCGI_UNKNOWN_TYPE 11 +#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) + +/* + * Value for requestId component of FCGI_Header + */ +#define FCGI_NULL_REQUEST_ID 0 + + +typedef struct { + unsigned char roleB1; + unsigned char roleB0; + unsigned char flags; + unsigned char reserved[5]; +} FCGI_BeginRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_BeginRequestBody body; +} FCGI_BeginRequestRecord; + +/* + * Mask for flags component of FCGI_BeginRequestBody + */ +#define FCGI_KEEP_CONN 1 + +/* + * Values for role component of FCGI_BeginRequestBody + */ +#define FCGI_RESPONDER 1 +#define FCGI_AUTHORIZER 2 +#define FCGI_FILTER 3 + + +typedef struct { + unsigned char appStatusB3; + unsigned char appStatusB2; + unsigned char appStatusB1; + unsigned char appStatusB0; + unsigned char protocolStatus; + unsigned char reserved[3]; +} FCGI_EndRequestBody; + +typedef struct { + FCGI_Header header; + FCGI_EndRequestBody body; +} FCGI_EndRequestRecord; + +/* + * Values for protocolStatus component of FCGI_EndRequestBody + */ +#define FCGI_REQUEST_COMPLETE 0 +#define FCGI_CANT_MPX_CONN 1 +#define FCGI_OVERLOADED 2 +#define FCGI_UNKNOWN_ROLE 3 + + +/* + * Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records + */ +#define FCGI_MAX_CONNS "FCGI_MAX_CONNS" +#define FCGI_MAX_REQS "FCGI_MAX_REQS" +#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" + + +typedef struct { + unsigned char type; + unsigned char reserved[7]; +} FCGI_UnknownTypeBody; + +typedef struct { + FCGI_Header header; + FCGI_UnknownTypeBody body; +} FCGI_UnknownTypeRecord; + +#endif /* _FASTCGI_H */ + Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,202 @@ +#include + +#include "settings.h" + +#include +#include +#include +#include +#include +#include + +#include "fdevent.h" +#include "buffer.h" + +fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) { + fdevents *ev; + + ev = calloc(1, sizeof(*ev)); + ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray)); + ev->maxfds = maxfds; + + switch(type) { + case FDEVENT_HANDLER_POLL: + if (0 != fdevent_poll_init(ev)) { + fprintf(stderr, "%s.%d: event-handler poll failed\n", + __FILE__, __LINE__); + + return NULL; + } + break; + case FDEVENT_HANDLER_SELECT: + if (0 != fdevent_select_init(ev)) { + fprintf(stderr, "%s.%d: event-handler select failed\n", + __FILE__, __LINE__); + return NULL; + } + break; + case FDEVENT_HANDLER_LINUX_RTSIG: + if (0 != fdevent_linux_rtsig_init(ev)) { + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + return NULL; + } + break; + case FDEVENT_HANDLER_LINUX_SYSEPOLL: + if (0 != fdevent_linux_sysepoll_init(ev)) { + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + return NULL; + } + break; + case FDEVENT_HANDLER_SOLARIS_DEVPOLL: + if (0 != fdevent_solaris_devpoll_init(ev)) { + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + return NULL; + } + break; + case FDEVENT_HANDLER_FREEBSD_KQUEUE: + if (0 != fdevent_freebsd_kqueue_init(ev)) { + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + return NULL; + } + break; + default: + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + return NULL; + } + + return ev; +} + +void fdevent_free(fdevents *ev) { + size_t i; + if (!ev) return; + + if (ev->free) ev->free(ev); + + for (i = 0; i < ev->maxfds; i++) { + if (ev->fdarray[i]) free(ev->fdarray[i]); + } + + free(ev->fdarray); + free(ev); +} + +int fdevent_reset(fdevents *ev) { + if (ev->reset) return ev->reset(ev); + + return 0; +} + +fdnode *fdnode_init() { + fdnode *fdn; + + fdn = calloc(1, sizeof(*fdn)); + fdn->fd = -1; + return fdn; +} + +void fdnode_free(fdnode *fdn) { + free(fdn); +} + +int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) { + fdnode *fdn; + + fdn = fdnode_init(); + fdn->handler = handler; + fdn->fd = fd; + fdn->ctx = ctx; + + ev->fdarray[fd] = fdn; + + return 0; +} + +int fdevent_unregister(fdevents *ev, int fd) { + fdnode *fdn; + if (!ev) return 0; + fdn = ev->fdarray[fd]; + + fdnode_free(fdn); + + ev->fdarray[fd] = NULL; + + return 0; +} + +int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) { + int fde = fde_ndx ? *fde_ndx : -1; + + if (ev->event_del) fde = ev->event_del(ev, fde, fd); + + if (fde_ndx) *fde_ndx = fde; + + return 0; +} + +int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) { + int fde = fde_ndx ? *fde_ndx : -1; + + if (ev->event_add) fde = ev->event_add(ev, fde, fd, events); + + if (fde_ndx) *fde_ndx = fde; + + return 0; +} + +int fdevent_poll(fdevents *ev, int timeout_ms) { + if (ev->poll == NULL) SEGFAULT(); + return ev->poll(ev, timeout_ms); +} + +int fdevent_event_get_revent(fdevents *ev, size_t ndx) { + if (ev->event_get_revent == NULL) SEGFAULT(); + + return ev->event_get_revent(ev, ndx); +} + +int fdevent_event_get_fd(fdevents *ev, size_t ndx) { + if (ev->event_get_fd == NULL) SEGFAULT(); + + return ev->event_get_fd(ev, ndx); +} + +fdevent_handler fdevent_get_handler(fdevents *ev, int fd) { + if (ev->fdarray[fd] == NULL) SEGFAULT(); + if (ev->fdarray[fd]->fd != fd) SEGFAULT(); + + return ev->fdarray[fd]->handler; +} + +void * fdevent_get_context(fdevents *ev, int fd) { + if (ev->fdarray[fd] == NULL) SEGFAULT(); + if (ev->fdarray[fd]->fd != fd) SEGFAULT(); + + return ev->fdarray[fd]->ctx; +} + +int fdevent_fcntl_set(fdevents *ev, int fd) { +#ifdef FD_CLOEXEC + /* close fd on exec (cgi) */ + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif + if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd); +#ifdef O_NONBLOCK + return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR); +#else + return 0; +#endif +} + + +int fdevent_event_next_fdndx(fdevents *ev, int ndx) { + if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx); + + return -1; +} + Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.h URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.h?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.h (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent.h Mon Jul 21 21:35:35 2008 @@ -0,0 +1,222 @@ +#ifndef _FDEVENT_H_ +#define _FDEVENT_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "settings.h" +#include "bitset.h" + +/* select event-system */ + +#if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H) +# if defined HAVE_STDINT_H +# include +# endif +# define USE_LINUX_EPOLL +# include +#endif + +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes + * under /usr/include/sys/ */ +#if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H)) +# define USE_POLL +# ifdef HAVE_POLL_H +# include +# else +# include +# endif +# if defined HAVE_SIGTIMEDWAIT && defined(__linux__) +# define USE_LINUX_SIGIO +# include +# endif +#endif + +#if defined HAVE_SELECT +# ifdef __WIN32 +# include +# endif +# define USE_SELECT +# ifdef HAVE_SYS_SELECT_H +# include +# endif +#endif + +#if defined HAVE_SYS_DEVPOLL_H && defined(__sun) +# define USE_SOLARIS_DEVPOLL +# include +#endif + +#if defined HAVE_SYS_EVENT_H && defined HAVE_KQUEUE +# define USE_FREEBSD_KQUEUE +# include +#endif + +#if defined HAVE_SYS_PORT_H && defined HAVE_PORT_CREATE +# define USE_SOLARIS_PORT +# include +#endif + + +typedef handler_t (*fdevent_handler)(void *srv, void *ctx, int revents); + +#define FDEVENT_IN BV(0) +#define FDEVENT_PRI BV(1) +#define FDEVENT_OUT BV(2) +#define FDEVENT_ERR BV(3) +#define FDEVENT_HUP BV(4) +#define FDEVENT_NVAL BV(5) + +typedef enum { FD_EVENT_TYPE_UNSET = -1, + FD_EVENT_TYPE_CONNECTION, + FD_EVENT_TYPE_FCGI_CONNECTION, + FD_EVENT_TYPE_DIRWATCH, + FD_EVENT_TYPE_CGI_CONNECTION +} fd_event_t; + +typedef enum { FDEVENT_HANDLER_UNSET, + FDEVENT_HANDLER_SELECT, + FDEVENT_HANDLER_POLL, + FDEVENT_HANDLER_LINUX_RTSIG, + FDEVENT_HANDLER_LINUX_SYSEPOLL, + FDEVENT_HANDLER_SOLARIS_DEVPOLL, + FDEVENT_HANDLER_FREEBSD_KQUEUE, + FDEVENT_HANDLER_SOLARIS_PORT +} fdevent_handler_t; + +/** + * a mapping from fd to connection structure + * + */ +typedef struct { + int fd; /**< the fd */ + void *conn; /**< a reference the corresponding data-structure */ + fd_event_t fd_type; /**< type of the fd */ + int events; /**< registered events */ + int revents; +} fd_conn; + +typedef struct { + fd_conn *ptr; + + size_t size; + size_t used; +} fd_conn_buffer; + +/** + * array of unused fd's + * + */ + +typedef struct _fdnode { + fdevent_handler handler; + void *ctx; + int fd; + + struct _fdnode *prev, *next; +} fdnode; + +typedef struct { + int *ptr; + + size_t used; + size_t size; +} buffer_int; + +/** + * fd-event handler for select(), poll() and rt-signals on Linux 2.4 + * + */ +typedef struct fdevents { + fdevent_handler_t type; + + fdnode **fdarray; + size_t maxfds; + +#ifdef USE_LINUX_SIGIO + int in_sigio; + int signum; + sigset_t sigset; + siginfo_t siginfo; + bitset *sigbset; +#endif +#ifdef USE_LINUX_EPOLL + int epoll_fd; + struct epoll_event *epoll_events; +#endif +#ifdef USE_POLL + struct pollfd *pollfds; + + size_t size; + size_t used; + + buffer_int unused; +#endif +#ifdef USE_SELECT + fd_set select_read; + fd_set select_write; + fd_set select_error; + + fd_set select_set_read; + fd_set select_set_write; + fd_set select_set_error; + + int select_max_fd; +#endif +#ifdef USE_SOLARIS_DEVPOLL + int devpoll_fd; + struct pollfd *devpollfds; +#endif +#ifdef USE_FREEBSD_KQUEUE + int kq_fd; + struct kevent *kq_results; + bitset *kq_bevents; +#endif +#ifdef USE_SOLARIS_PORT + int port_fd; +#endif + int (*reset)(struct fdevents *ev); + void (*free)(struct fdevents *ev); + + int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events); + int (*event_del)(struct fdevents *ev, int fde_ndx, int fd); + int (*event_get_revent)(struct fdevents *ev, size_t ndx); + int (*event_get_fd)(struct fdevents *ev, size_t ndx); + + int (*event_next_fdndx)(struct fdevents *ev, int ndx); + + int (*poll)(struct fdevents *ev, int timeout_ms); + + int (*fcntl_set)(struct fdevents *ev, int fd); +} fdevents; + +fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type); +int fdevent_reset(fdevents *ev); +void fdevent_free(fdevents *ev); + +int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events); +int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd); +int fdevent_event_get_revent(fdevents *ev, size_t ndx); +int fdevent_event_get_fd(fdevents *ev, size_t ndx); +fdevent_handler fdevent_get_handler(fdevents *ev, int fd); +void * fdevent_get_context(fdevents *ev, int fd); + +int fdevent_event_next_fdndx(fdevents *ev, int ndx); + +int fdevent_poll(fdevents *ev, int timeout_ms); + +int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx); +int fdevent_unregister(fdevents *ev, int fd); + +int fdevent_fcntl_set(fdevents *ev, int fd); + +int fdevent_select_init(fdevents *ev); +int fdevent_poll_init(fdevents *ev); +int fdevent_linux_rtsig_init(fdevents *ev); +int fdevent_linux_sysepoll_init(fdevents *ev); +int fdevent_solaris_devpoll_init(fdevents *ev); +int fdevent_freebsd_kqueue_init(fdevents *ev); + +#endif + + Added: webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent_freebsd_kqueue.c URL: http://svn.apache.org/viewvc/webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent_freebsd_kqueue.c?rev=678637&view=auto ============================================================================== --- webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent_freebsd_kqueue.c (added) +++ webservices/axis2/branches/c/lighttpd_mod_axis2/lighttpd/src/fdevent_freebsd_kqueue.c Mon Jul 21 21:35:35 2008 @@ -0,0 +1,207 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "fdevent.h" +#include "settings.h" +#include "buffer.h" +#include "server.h" + +#ifdef USE_FREEBSD_KQUEUE +#include +#include + +static void fdevent_freebsd_kqueue_free(fdevents *ev) { + close(ev->kq_fd); + free(ev->kq_results); + bitset_free(ev->kq_bevents); +} + +static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) { + int filter, ret; + struct kevent kev; + struct timespec ts; + + if (fde_ndx < 0) return -1; + + filter = bitset_test_bit(ev->kq_bevents, fd) ? EVFILT_READ : EVFILT_WRITE; + + EV_SET(&kev, fd, filter, EV_DELETE, 0, 0, NULL); + + ts.tv_sec = 0; + ts.tv_nsec = 0; + + ret = kevent(ev->kq_fd, + &kev, 1, + NULL, 0, + &ts); + + if (ret == -1) { + fprintf(stderr, "%s.%d: kqueue failed polling: %s\n", + __FILE__, __LINE__, strerror(errno)); + + return -1; + } + + return -1; +} + +static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, int events) { + int filter, ret; + struct kevent kev; + struct timespec ts; + + UNUSED(fde_ndx); + + filter = (events & FDEVENT_IN) ? EVFILT_READ : EVFILT_WRITE; + + EV_SET(&kev, fd, filter, EV_ADD|EV_CLEAR, 0, 0, NULL); + + ts.tv_sec = 0; + ts.tv_nsec = 0; + + ret = kevent(ev->kq_fd, + &kev, 1, + NULL, 0, + &ts); + + if (ret == -1) { + fprintf(stderr, "%s.%d: kqueue failed polling: %s\n", + __FILE__, __LINE__, strerror(errno)); + + return -1; + } + + if (filter == EVFILT_READ) { + bitset_set_bit(ev->kq_bevents, fd); + } else { + bitset_clear_bit(ev->kq_bevents, fd); + } + + return fd; +} + +static int fdevent_freebsd_kqueue_poll(fdevents *ev, int timeout_ms) { + int ret; + struct timespec ts; + + ts.tv_sec = timeout_ms / 1000; + ts.tv_nsec = (timeout_ms % 1000) * 1000000; + + ret = kevent(ev->kq_fd, + NULL, 0, + ev->kq_results, ev->maxfds, + &ts); + + if (ret == -1) { + switch(errno) { + case EINTR: + /* we got interrupted, perhaps just a SIGCHLD of a CGI script */ + return 0; + default: + fprintf(stderr, "%s.%d: kqueue failed polling: %s\n", + __FILE__, __LINE__, strerror(errno)); + break; + } + } + + return ret; +} + +static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) { + int events = 0, e; + + e = ev->kq_results[ndx].filter; + + if (e == EVFILT_READ) { + events |= FDEVENT_IN; + } else if (e == EVFILT_WRITE) { + events |= FDEVENT_OUT; + } + + e = ev->kq_results[ndx].flags; + + if (e & EV_EOF) { + events |= FDEVENT_HUP; + } + + if (e & EV_ERROR) { + events |= FDEVENT_ERR; + } + + return events; +} + +static int fdevent_freebsd_kqueue_event_get_fd(fdevents *ev, size_t ndx) { + return ev->kq_results[ndx].ident; +} + +static int fdevent_freebsd_kqueue_event_next_fdndx(fdevents *ev, int ndx) { + UNUSED(ev); + + return (ndx < 0) ? 0 : ndx + 1; +} + +static int fdevent_freebsd_kqueue_reset(fdevents *ev) { + if (-1 == (ev->kq_fd = kqueue())) { + fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__, strerror(errno)); + + return -1; + } + + return 0; +} + + +int fdevent_freebsd_kqueue_init(fdevents *ev) { + ev->type = FDEVENT_HANDLER_FREEBSD_KQUEUE; +#define SET(x) \ + ev->x = fdevent_freebsd_kqueue_##x; + + SET(free); + SET(poll); + SET(reset); + + SET(event_del); + SET(event_add); + + SET(event_next_fdndx); + SET(event_get_fd); + SET(event_get_revent); + + ev->kq_fd = -1; + + ev->kq_results = calloc(ev->maxfds, sizeof(*ev->kq_results)); + ev->kq_bevents = bitset_init(ev->maxfds); + + /* check that kqueue works */ + + if (-1 == (ev->kq_fd = kqueue())) { + fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__, strerror(errno)); + + return -1; + } + + close(ev->kq_fd); + ev->kq_fd = -1; + + return 0; +} +#else +int fdevent_freebsd_kqueue_init(fdevents *ev) { + UNUSED(ev); + + fprintf(stderr, "%s.%d: kqueue not available, try to set server.event-handler = \"poll\" or \"select\"\n", + __FILE__, __LINE__); + + return -1; +} +#endif