# HG changeset patch # User Igor Sysoev # Date 1044552073 0 # Node ID e8cdc2989ceec297d90340fcbd3c8bfe7632179d # Parent 6b13b1cadabe8f02990f67939ba7e1caceef33b4 nginx-0.0.1-2003-02-06-20:21:13 import diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -27,6 +27,7 @@ static void ngx_open_listening_sockets(n /* STUB */ int ngx_max_conn = 512; +u_int ngx_sendfile_flags; ngx_server_t ngx_server; /* */ @@ -53,12 +54,17 @@ int main(int argc, char *const *argv) /* */ #if (WIN32) - ngx_init_sockets(&ngx_log); + + if (ngx_init_sockets(&ngx_log) == NGX_ERROR) { + exit(1); + } + #else + ngx_set_signals(&ngx_log); + #endif - ngx_init_array(ngx_listening_sockets, ngx_pool, 10, sizeof(ngx_listen_t), 1); diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -62,7 +62,9 @@ char *ngx_conf_parse(ngx_conf_t *cf, ngx /* NGX_OK, NGX_ERROR, NGX_CONF_FILE_DONE, NGX_CONF_BLOCK_DONE */ +#if 0 ngx_log_debug(cf->log, "token %d" _ rc); +#endif if (rc == NGX_ERROR) { return NGX_CONF_ERROR; @@ -101,7 +103,9 @@ ngx_log_debug(cf->log, "token %d" _ rc); && ngx_strcmp(name->data, cmd->name.data) == 0) { +#if 0 ngx_log_debug(cf->log, "command '%s'" _ cmd->name.data); +#endif if (!(cmd->type & NGX_CONF_ANY) && !(cmd->type & argument_number[cf->args->nelts - 1])) @@ -126,7 +130,9 @@ ngx_log_debug(cf->log, "command '%s'" _ rv = cmd->set(cf, cmd, conf); +#if 0 ngx_log_debug(cf->log, "rv: %d" _ rv); +#endif if (rv == NGX_CONF_OK) { found = 1; @@ -192,7 +198,9 @@ static int ngx_conf_read_token(ngx_conf_ h = cf->conf_file->hunk; start = h->pos.mem; +#if 0 ngx_log_debug(cf->log, "TOKEN START"); +#endif for ( ;; ) { @@ -360,7 +368,9 @@ ngx_log_debug(cf->log, "%d:%d:%d:%d:%d ' *dst = '\0'; word->len = len; +#if 0 ngx_log_debug(cf->log, "FOUND %d:'%s'" _ word->len _ word->data); +#endif if (ch == ';' || ch == '{') { return NGX_OK; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -83,6 +83,12 @@ struct ngx_conf_s { } +#define ngx_conf_size_merge(conf, prev, default) \ + if (conf == (size_t) NGX_CONF_UNSET) { \ + conf = (prev == (size_t) NGX_CONF_UNSET) ? default : prev; \ + } + + char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); @@ -95,4 +101,4 @@ char *ngx_conf_set_time_slot(ngx_conf_t extern ngx_module_t *ngx_modules[]; -#endif _NGX_HTTP_CONF_FILE_H_INCLUDED_ +#endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -94,22 +94,24 @@ #include #include + #ifndef HAVE_POLL #define HAVE_POLL 1 #include -/* -#ifndef INFTIM -#define INFTIM -1 -#endif -*/ #endif #if (HAVE_DEVPOLL) +#include #include /* Solaris, HP/UX */ #endif +#if (HAVE_AIO) +#include +#endif + + #define ngx_inline inline diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -38,6 +38,11 @@ struct ngx_connection_s { int family; struct sockaddr *sockaddr; socklen_t socklen; +#if (HAVE_IOCP) + struct sockaddr *local_sockaddr; + socklen_t local_socklen; + void *listening; +#endif int addr; int addr_text_max_len; ngx_str_t addr_text; diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -21,4 +21,4 @@ struct ngx_file_s { }; -#endif _NGX_FILE_H_INCLUDED_ +#endif /* _NGX_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_listen.h b/src/core/ngx_listen.h --- a/src/core/ngx_listen.h +++ b/src/core/ngx_listen.h @@ -36,6 +36,7 @@ typedef struct { unsigned bound:1; /* already bound */ unsigned inherited:1; /* inherited from previous process */ + unsigned nonblocking_accept:1; unsigned nonblocking:1; #if 0 unsigned overlapped:1; /* Winsock2 overlapped */ diff --git a/src/core/ngx_sendfile.h b/src/core/ngx_sendfile.h --- a/src/core/ngx_sendfile.h +++ b/src/core/ngx_sendfile.h @@ -7,14 +7,17 @@ #include #include #include +#include #include -int ngx_sendfile(ngx_socket_t s, +int ngx_sendfile(ngx_connection_t *c, ngx_iovec_t *headers, int hdr_cnt, ngx_fd_t fd, off_t offset, size_t nbytes, ngx_iovec_t *trailers, int trl_cnt, - off_t *sent, - ngx_log_t *log); + off_t *sent, u_int flags); + + +extern u_int ngx_sendfile_flags; #endif /* _NGX_SENDFILE_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -16,6 +16,7 @@ #error "/dev/poll is not supported on this platform" #endif +static int ngx_devpoll_set_event(ngx_event_t *ev, int event, u_int flags); /* STUB */ #define DEVPOLL_NCHANGES 512 @@ -137,7 +138,7 @@ int ngx_devpoll_del_event(ngx_event_t *e } -int ngx_devpoll_set_event(ngx_event_t *ev, int event, u_int flags) +static int ngx_devpoll_set_event(ngx_event_t *ev, int event, u_int flags) { int n; ngx_connection_t *c; @@ -192,7 +193,6 @@ int ngx_devpoll_process_events(ngx_log_t int events, n, i; ngx_msec_t timer, delta; ngx_err_t err; - ngx_event_t *ev; ngx_connection_t *c; struct dvpoll dvp; struct timeval tv; @@ -233,7 +233,7 @@ int ngx_devpoll_process_events(ngx_log_t nchanges = 0; - if (timer != INFTIM) { + if ((int) timer != INFTIM) { gettimeofday(&tv, NULL); delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta; @@ -305,7 +305,7 @@ int ngx_devpoll_process_events(ngx_log_t } } - if (timer != INFTIM) { + if ((int) timer != INFTIM) { ngx_event_expire_timers(delta); } diff --git a/src/event/modules/ngx_iocp_module.c b/src/event/modules/ngx_iocp_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_iocp_module.c @@ -0,0 +1,137 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +int ngx_iocp_threads = 0;; + + +static HANDLE iocp; +static ngx_event_t *timer_queue; + + +int ngx_iocp_init(int max_connections, ngx_log_t *log) +{ + iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, + NULL, 0, ngx_iocp_threads); + + if (iocp == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "CreateIoCompletionPort() failed"); + return NGX_ERROR; + } + + timer_queue = ngx_event_init_timer(log); + if (timer_queue == NULL) { + return NGX_ERROR; + } + + ngx_event_actions.process = ngx_iocp_process_events; + + ngx_event_flags = NGX_HAVE_AIO_EVENT|NGX_HAVE_IOCP_EVENT; + + return NGX_OK; +} + + +int ngx_iocp_add_event(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = (ngx_connection_t *) ev->data; + + ngx_log_debug(ev->log, "iocp: %d, %08x:%08x" _ c->fd _ ev _ &ev->ovlp); + + if (CreateIoCompletionPort((HANDLE) c->fd, iocp, (DWORD) ev, 0) == NULL) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + "CreateIoCompletionPort() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +int ngx_iocp_process_events(ngx_log_t *log) +{ + int rc; + size_t bytes; + ngx_err_t err; + ngx_msec_t timer, delta; + ngx_event_t *ev, *e; + ngx_event_ovlp_t *ovlp; + + ngx_log_debug(log, "iocp"); + + timer = ngx_event_find_timer(); + + if (timer) { + delta = ngx_msec(); + + } else { + timer = INFINITE; + delta = 0; + } + + ngx_log_debug(log, "iocp timer: %d" _ timer); + +#if 1 + rc = GetQueuedCompletionStatus(iocp, &bytes, (LPDWORD) &e, + (LPOVERLAPPED *) &ovlp, timer); + ngx_log_debug(log, "iocp: %d, %d:%08x:%08x" _ rc _ bytes _ e _ ovlp); + if (rc == 0) { +#else + if (GetQueuedCompletionStatus(iocp, &bytes, (LPDWORD) &e, + (LPOVERLAPPED *) &ovlp, timer) == 0) { +#endif + err = ngx_errno; + + if (ovlp == NULL) { + if (err != WAIT_TIMEOUT) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "GetQueuedCompletionStatus() failed"); + + return NGX_ERROR; + } + + } else { + ovlp->error = err; + } + } + + if (timer != INFINITE) { + delta = ngx_msec() - delta; + } + + if (ovlp) { + ev = ovlp->event; + +ngx_log_debug(log, "iocp ev: %08x" _ ev); + + if (ev == e) { + ev->ready = 1; + ev->available = bytes; + } + +ngx_log_debug(log, "iocp ev: %08x" _ ev->event_handler); + + if (ev->event_handler(ev) == NGX_ERROR) { + ev->close_handler(ev); + } + } + + if (timer != INFINITE) { + ngx_event_expire_timers(delta); + } + + return NGX_OK; +} diff --git a/src/event/modules/ngx_iocp_module.h b/src/event/modules/ngx_iocp_module.h new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_iocp_module.h @@ -0,0 +1,15 @@ +#ifndef _NGX_IOCP_MODULE_H_INCLUDED_ +#define _NGX_IOCP_MODULE_H_INCLUDED_ + + +#include +#include +#include + + +int ngx_iocp_init(int max_connections, ngx_log_t *log); +int ngx_iocp_add_event(ngx_event_t *ev); +int ngx_iocp_process_events(ngx_log_t *log); + + +#endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -23,7 +23,11 @@ /* should be per-thread */ +#if 1 +int kq; +#else static int kq; +#endif static struct kevent *change_list, *event_list; static unsigned int nchanges; static int nevents; @@ -63,7 +67,12 @@ int ngx_kqueue_init(int max_connections, ngx_event_actions.process = ngx_kqueue_process_events; ngx_event_flags = NGX_HAVE_LEVEL_EVENT - |NGX_HAVE_ONESHOT_EVENT|NGX_HAVE_CLEAR_EVENT; + |NGX_HAVE_ONESHOT_EVENT +#if (HAVE_AIO_EVENT) + |NGX_HAVE_AIO_EVENT; +#else + |NGX_HAVE_CLEAR_EVENT; +#endif #endif return NGX_OK; @@ -221,10 +230,19 @@ int ngx_kqueue_process_events(ngx_log_t for (i = 0; i < events; i++) { #if (NGX_DEBUG_EVENT) - ngx_log_debug(log, "kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _ - event_list[i].ident _ event_list[i].filter _ - event_list[i].flags _ event_list[i].fflags _ - event_list[i].data _ event_list[i].udata); + if (event_list[i].ident > 0x8000000) { + ngx_log_debug(log, + "kevent: %08x: ft:%d f:%08x ff:%08x d:%d ud:%08x" _ + event_list[i].ident _ event_list[i].filter _ + event_list[i].flags _ event_list[i].fflags _ + event_list[i].data _ event_list[i].udata); + } else { + ngx_log_debug(log, + "kevent: %d: ft:%d f:%08x ff:%08x d:%d ud:%08x" _ + event_list[i].ident _ event_list[i].filter _ + event_list[i].flags _ event_list[i].fflags _ + event_list[i].data _ event_list[i].udata); + } #endif if (event_list[i].flags & EV_ERROR) { @@ -243,7 +261,6 @@ int ngx_kqueue_process_events(ngx_log_t case EVFILT_READ: case EVFILT_WRITE: - ev->ready = 1; ev->available = event_list[i].data; if (event_list[i].flags & EV_EOF) { @@ -255,12 +272,18 @@ int ngx_kqueue_process_events(ngx_log_t ngx_del_timer(ev); } + /* fall through */ + + case EVFILT_AIO: + ev->ready = 1; + if (ev->event_handler(ev) == NGX_ERROR) { ev->close_handler(ev); } break; + default: ngx_log_error(NGX_LOG_ALERT, log, 0, "unknown kevent filter %d" _ event_list[i].filter); diff --git a/src/event/modules/ngx_kqueue_module.h b/src/event/modules/ngx_kqueue_module.h --- a/src/event/modules/ngx_kqueue_module.h +++ b/src/event/modules/ngx_kqueue_module.h @@ -14,4 +14,10 @@ void ngx_kqueue_add_timer(ngx_event_t *e int ngx_kqueue_process_events(ngx_log_t *log); +#if 1 +extern int kq; +#endif + + + #endif /* _NGX_KQUEUE_MODULE_H_INCLUDED_ */ diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -13,7 +13,7 @@ /* should be per-thread */ static struct pollfd *event_list; -static unsigned int nevents; +static u_int nevents; static ngx_event_t **event_index; static ngx_event_t **ready_index; @@ -140,7 +140,8 @@ int ngx_poll_del_event(ngx_event_t *ev, int ngx_poll_process_events(ngx_log_t *log) { - int i, ready, nready, found; + int ready, found; + u_int i, nready; ngx_msec_t timer, delta; ngx_err_t err; ngx_event_t *ev; @@ -172,7 +173,7 @@ int ngx_poll_process_events(ngx_log_t *l ngx_log_debug(log, "poll ready %d" _ ready); - if (timer != INFTIM) { + if ((int) timer != INFTIM) { delta = ngx_msec() - delta; } else { @@ -256,7 +257,7 @@ int ngx_poll_process_events(ngx_log_t *l ngx_log_error(NGX_LOG_ALERT, log, 0, "poll ready != events"); } - if (timer != INFTIM) { + if ((int) timer != INFTIM) { ngx_event_expire_timers(delta); } diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -23,7 +23,7 @@ static int max_write; static int max_fd; #endif -static int nevents; +static u_int nevents; static ngx_event_t **event_index; static ngx_event_t **ready_index; @@ -177,8 +177,8 @@ int ngx_select_del_event(ngx_event_t *ev int ngx_select_process_events(ngx_log_t *log) { - int ready, found, nready; - u_int i; + int ready, found; + u_int i, nready; ngx_msec_t timer, delta; ngx_event_t *ev; ngx_connection_t *c; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -12,16 +12,24 @@ #include #include + #if (HAVE_POLL) #include #endif + #if (HAVE_DEVPOLL) #include #endif + #if (HAVE_KQUEUE) #include #endif +#if (HAVE_IOCP) +#include +#include +#endif + ngx_connection_t *ngx_connections; ngx_event_t *ngx_read_events, *ngx_write_events; @@ -68,7 +76,10 @@ static int (*ngx_event_init[]) (int max_ ngx_devpoll_init, #endif #if (HAVE_KQUEUE) - ngx_kqueue_init + ngx_kqueue_init, +#endif +#if (HAVE_IOCP) + ngx_iocp_init #endif }; @@ -86,6 +97,10 @@ void ngx_pre_thread(ngx_array_t *ls, ngx /* STUB */ int max_connections = 512; +#if (HAVE_IOCP) + ngx_event_type = NGX_IOCP_EVENT; +#endif + if (ngx_init_events(max_connections, log) == NGX_ERROR) { exit(1); } @@ -127,16 +142,38 @@ void ngx_pre_thread(ngx_array_t *ls, ngx ngx_memcpy(ev->log, c->log, sizeof(ngx_log_t)); c->read = ev; ev->data = c; - ev->event_handler = &ngx_event_accept; + ev->index = NGX_INVALID_INDEX; +#if 0 ev->listening = 1; - ev->index = NGX_INVALID_INDEX; +#endif ev->available = 0; #if (HAVE_DEFERRED_ACCEPT) ev->deferred_accept = s[i].deferred_accept; #endif + +#if (HAVE_IOCP) + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + ev->event_handler = &ngx_event_acceptex; + + if (ngx_iocp_add_event(ev) == NGX_ERROR) { + return NGX_ERROR; + } + + ngx_event_post_acceptex(&s[i], 1); + + } else { + ev->event_handler = &ngx_event_accept; + } + +#else + + ev->event_handler = &ngx_event_accept; ngx_add_event(ev, NGX_READ_EVENT, 0); + +#endif } } diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -15,6 +15,15 @@ typedef struct ngx_event_s ngx_event_t; +#if (HAVE_IOCP) +typedef struct { + WSAOVERLAPPED ovlp; + ngx_event_t *event; + int error; +} ngx_event_ovlp_t; +#endif + + struct ngx_event_s { void *data; @@ -45,11 +54,11 @@ struct ngx_event_s { /* otherwise: */ /* accept: 1 if accept many, 0 otherwise */ - /* flags - int are probably faster on write then bits ??? */ - unsigned oneshot:1; +#if 0 unsigned listening:1; +#endif unsigned write:1; unsigned active:1; @@ -66,11 +75,24 @@ struct ngx_event_s { #if (HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; #endif + #if (HAVE_KQUEUE) unsigned eof:1; int error; #endif + +#if (HAVE_AIO) + +#if (HAVE_IOCP) + ngx_event_ovlp_t ovlp; +#else + struct aiocb aiocb; +#endif + +#endif + + #if 0 void *thr_ctx; /* event thread context if $(CC) doesn't understand __thread declaration @@ -94,6 +116,10 @@ typedef enum { #if (HAVE_KQUEUE) NGX_KQUEUE_EVENT, #endif +#if (HAVE_IOCP) + NGX_IOCP_EVENT, +#endif + NGX_DUMMY_EVENT /* avoid comma at end of enumerator list */ } ngx_event_type_e ; typedef struct { @@ -125,6 +151,10 @@ typedef struct { /* No need to add or delete event filters - overlapped, aio_read, aioread */ #define NGX_HAVE_AIO_EVENT 16 +/* Need to add socket or halde only once - i/o completion port. + It also requires to set HAVE_AIO_EVENT and NGX_HAVE_AIO_EVENT */ +#define NGX_HAVE_IOCP_EVENT 32 + /* Event filter is deleted before closing file. Has no meaning for select, poll, epoll. @@ -187,43 +217,26 @@ typedef struct { #define ngx_process_events ngx_event_actions.process #define ngx_add_event ngx_event_actions.add #define ngx_del_event ngx_event_actions.del + #if 0 #define ngx_add_timer ngx_event_actions.timer #else #define ngx_add_timer ngx_event_add_timer #endif + +#if (HAVE_IOCP_EVENT) +#define ngx_event_recv ngx_event_wsarecv +#elif (HAVE_AIO_EVENT) +#define ngx_event_recv ngx_event_aio_read +#else #define ngx_event_recv ngx_event_recv_core +#endif #endif #define ngx_del_timer ngx_event_del_timer -#if 0 -ngx_inline static void ngx_del_timer(ngx_event_t *ev) -{ -#if (NGX_DEBUG_EVENT) - /* STUB - we can not cast (ngx_connection_t *) here */ - ngx_log_debug(ev->log, "del timer: %d" _ *(int *)(ev->data)); -#endif - - if (ev->timer_prev) { - ev->timer_prev->timer_next = ev->timer_next; - } - - if (ev->timer_next) { - ev->timer_next->timer_delta += ev->timer_delta; - ev->timer_next->timer_prev = ev->timer_prev; - ev->timer_next = NULL; - } - - if (ev->timer_prev) { - ev->timer_prev = NULL; - } -} -#endif - - extern ngx_event_t *ngx_read_events; extern ngx_event_t *ngx_write_events; @@ -236,6 +249,10 @@ extern int ngx_event_f #endif +ssize_t ngx_event_recv_core(ngx_connection_t *c, char *buf, size_t size); +int ngx_event_close_connection(ngx_event_t *ev); + + void ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log); void ngx_worker(ngx_log_t *log); diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -31,7 +31,9 @@ int ngx_event_accept(ngx_event_t *ev) ev->ready = 0; +#if 0 /* DEBUG */ ev->available++; +#endif do { ngx_test_null(pool, ngx_create_pool(ls->pool_size, ev->log), NGX_OK); @@ -55,13 +57,40 @@ int ngx_event_accept(ngx_event_t *ev) return NGX_OK; } -#if !(HAVE_INHERITED_NONBLOCK) + +#if (HAVE_INHERITED_NONBLOCK) + +#if (HAVE_AIO_EVENT) + if ((ngx_event_flags & NGX_HAVE_AIO_EVENT)) { + if (ngx_blocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, + ngx_blocking_n " %s failed", ls->addr_text.data); + return NGX_OK; + } + } +#endif + +#else /* !HAVE_INHERITED_NONBLOCK */ + +#if (HAVE_AIO_EVENT) + if (!(ngx_event_flags & NGX_HAVE_AIO_EVENT)) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", ls->addr_text.data); + return NGX_OK; + } + } +#else if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " %s failed", ls->addr_text.data); + return NGX_OK; } #endif +#endif /* HAVE_INHERITED_NONBLOCK */ + + rev = &ngx_read_events[s]; wev = &ngx_write_events[s]; c = &ngx_connections[s]; @@ -88,9 +117,15 @@ int ngx_event_accept(ngx_event_t *ev) c->fd = s; c->unexpected_eof = 1; wev->write = 1; - wev->ready = 1; - wev->timer = rev->timer = 10000; +#if (HAVE_AIO_EVENT) + if (!(ngx_event_flags & NGX_HAVE_AIO_EVENT)) { + wev->ready = 1; + } +#endif + + /* STUB ? */ wev->timer = rev->timer = 10000; + wev->timer_handler = rev->timer_handler = ngx_event_close_connection; wev->close_handler = rev->close_handler = ngx_event_close_connection; diff --git a/src/event/ngx_event_acceptex.c b/src/event/ngx_event_acceptex.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_acceptex.c @@ -0,0 +1,150 @@ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + +/* This function should always return NGX_OK even there are some failures + because if we return NGX_ERROR then listening socket would be closed */ + +int ngx_event_acceptex(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = (ngx_connection_t *) ev->data; + + if (ev->ovlp.error) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ev->ovlp.error, + "AcceptEx(%s) falied", c->addr_text.data); + return NGX_OK; + } + + GetAcceptExSockaddrs(c->data, 0, + c->socklen + 16, c->socklen + 16, + &c->local_sockaddr, &c->local_socklen, + &c->sockaddr, &c->socklen); + + ngx_event_post_acceptex(c->listening, 1); + + /* STUB: InterlockedInc() */ + c->number = ngx_connection_counter++; + + c->handler(c); + + return NGX_OK; + +} + + +int ngx_event_post_acceptex(ngx_listen_t *ls, int n) +{ + int i; + u_int rcvd; + ngx_err_t err; + ngx_pool_t *pool; + ngx_event_t *rev, *wev; + ngx_socket_t s; + ngx_connection_t *c; + + for (i = 0; i < n; i++) { + + /* TODO: look up reused sockets */ + + ngx_log_debug(ls->log, "socket: %x" _ ls->flags); + + s = ngx_socket(ls->family, ls->type, ls->protocol, ls->flags); + + if (s == -1) { + ngx_log_error(NGX_LOG_ALERT, ls->log, ngx_socket_errno, + ngx_socket_n " for AcceptEx(%s) falied", + ls->addr_text.data); + + return NGX_ERROR; + } + + ngx_test_null(pool, ngx_create_pool(ls->pool_size, ls->log), NGX_ERROR); + + rev = &ngx_read_events[s]; + wev = &ngx_write_events[s]; + c = &ngx_connections[s]; + + ngx_memzero(rev, sizeof(ngx_event_t)); + ngx_memzero(wev, sizeof(ngx_event_t)); + ngx_memzero(c, sizeof(ngx_connection_t)); + + c->pool = pool; + + rev->index = wev->index = NGX_INVALID_INDEX; + + rev->ovlp.event = rev; + wev->ovlp.event = wev; + + rev->data = wev->data = c; + c->read = rev; + c->write = wev; + + c->family = ls->family; + c->socklen = ls->socklen; + c->addr = ls->addr; + c->addr_text_max_len = ls->addr_text_max_len; + c->post_accept_timeout = ls->post_accept_timeout; + + c->listening = ls; + c->fd = s; + + c->unexpected_eof = 1; + wev->write = 1; + + c->handler = ls->handler; + rev->event_handler = ngx_event_acceptex; + + wev->timer_handler = rev->timer_handler = ngx_event_close_connection; + wev->close_handler = rev->close_handler = ngx_event_close_connection; + + c->ctx = ls->ctx; + c->servers = ls->servers; + + ngx_test_null(c->data, ngx_palloc(pool, 2 * (c->socklen + 16)), + NGX_ERROR); + ngx_test_null(c->local_sockaddr, ngx_palloc(pool, c->socklen), + NGX_ERROR); + ngx_test_null(c->sockaddr, ngx_palloc(pool, c->socklen), + NGX_ERROR); + + ngx_test_null(c->log, ngx_palloc(c->pool, sizeof(ngx_log_t)), + NGX_ERROR); + ngx_memcpy(c->log, ls->log, sizeof(ngx_log_t)); + rev->log = wev->log = c->log; + + if (ngx_iocp_add_event(rev) == NGX_ERROR) { + return NGX_ERROR; + } + + if (AcceptEx(ls->fd, s, c->data, 0, + c->socklen + 16, c->socklen + 16, + &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0) { + + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, ls->log, err, + "AcceptEx(%s) falied", ls->addr_text.data); + + return NGX_ERROR; + } + } + + return NGX_OK; +} diff --git a/src/event/ngx_event_acceptex.h b/src/event/ngx_event_acceptex.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_acceptex.h @@ -0,0 +1,13 @@ +#ifndef _NGX_EVENT_ACCEPTEX_H_INCLUDED_ +#define _NGX_EVENT_ACCEPTEX_H_INCLUDED_ + + +#include +#include + + +int ngx_event_acceptex(ngx_event_t *ev); +int ngx_event_post_acceptex(ngx_listen_t *ls, int n); + + +#endif /* _NGX_EVENT_ACCEPTEX_H_INCLUDED_ */ diff --git a/src/event/ngx_event_aio_read.c b/src/event/ngx_event_aio_read.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_aio_read.c @@ -0,0 +1,113 @@ + +#include +#include +#include +#include +#include +#include +#include + +#if (HAVE_KQUEUE) +#include +#endif + + +/* + The data is ready - 3 syscalls: + aio_read(), aio_error(), aio_return() + The data is not ready - 4 (kqueue) or 5 syscalls: + aio_read(), aio_error(), notifiction, + aio_error(), aio_return() + aio_cancel(), aio_error() +*/ + +ssize_t ngx_event_aio_read(ngx_connection_t *c, char *buf, size_t size) +{ + int rc, first, canceled; + ngx_event_t *ev; + + ev = c->read; + + canceled = 0; + + if (ev->timedout) { + ngx_set_socket_errno(NGX_ETIMEDOUT); + ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_read() timed out"); + + rc = aio_cancel(c->fd, &ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, + "aio_cancel() failed"); + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_cancel: %d" _ rc); + + canceled = 1; + + ev->ready = 1; + } + + first = 0; + + if (!ev->ready) { + ngx_memzero(&ev->aiocb, sizeof(struct aiocb)); + + ev->aiocb.aio_fildes = c->fd; + ev->aiocb.aio_buf = buf; + ev->aiocb.aio_nbytes = size; + +#if (HAVE_KQUEUE) + ev->aiocb.aio_sigevent.sigev_notify_kqueue = kq; + ev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; + ev->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; +#endif + + if (aio_read(&ev->aiocb) == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, + "aio_read() failed"); + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_read: OK"); + + ev->active = 1; + first = 1; + } + + ev->ready = 0; + + rc = aio_error(&ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_error() failed"); + return NGX_ERROR; + } + + if (rc != 0) { + if (rc == NGX_EINPROGRESS) { + if (!first) { + ngx_log_error(NGX_LOG_CRIT, ev->log, rc, + "aio_read() still in progress"); + } + return NGX_AGAIN; + } + + if (rc == NGX_ECANCELED && canceled) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_CRIT, ev->log, rc, "aio_read() failed"); + return NGX_ERROR; + } + + rc = aio_return(&ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_return() failed"); + + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_read: %d" _ rc); + + return rc; +} diff --git a/src/event/ngx_event_aio_write.c b/src/event/ngx_event_aio_write.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_aio_write.c @@ -0,0 +1,115 @@ + +#include +#include +#include +#include +#include +#include + +#if (HAVE_KQUEUE) +#include +#endif + + +/* + The data is ready - 3 syscalls: + aio_write(), aio_error(), aio_return() + The data is not ready - 4 (kqueue) or 5 syscalls: + aio_write(), aio_error(), notifiction, + aio_error(), aio_return() + aio_cancel(), aio_error() +*/ + +ssize_t ngx_event_aio_write(ngx_connection_t *c, char *buf, size_t size) +{ + int rc, first, canceled; + ngx_event_t *ev; + + ev = c->write; + + canceled = 0; + +ngx_log_debug(ev->log, "aio: ev->ready: %d" _ ev->ready); +ngx_log_debug(ev->log, "aio: aiocb: %08x" _ &ev->aiocb); + + if (ev->timedout) { + ngx_set_socket_errno(NGX_ETIMEDOUT); + ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_write() timed out"); + + rc = aio_cancel(c->fd, &ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, + "aio_cancel() failed"); + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_cancel: %d" _ rc); + + canceled = 1; + + ev->ready = 1; + } + + first = 0; + + if (!ev->ready) { + ngx_memzero(&ev->aiocb, sizeof(struct aiocb)); + + ev->aiocb.aio_fildes = c->fd; + ev->aiocb.aio_buf = buf; + ev->aiocb.aio_nbytes = size; + +#if (HAVE_KQUEUE) + ev->aiocb.aio_sigevent.sigev_notify_kqueue = kq; + ev->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT; + ev->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev; +#endif + + if (aio_write(&ev->aiocb) == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, + "aio_write() failed"); + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_write: OK"); + + ev->active = 1; + first = 1; + } + + ev->ready = 0; + + rc = aio_error(&ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_error() failed"); + return NGX_ERROR; + } + + if (rc != 0) { + if (rc == NGX_EINPROGRESS) { + if (!first) { + ngx_log_error(NGX_LOG_CRIT, ev->log, rc, + "aio_write() still in progress"); + } + return NGX_AGAIN; + } + + if (rc == NGX_ECANCELED && canceled) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_CRIT, ev->log, rc, "aio_write() failed"); + return NGX_ERROR; + } + + rc = aio_return(&ev->aiocb); + if (rc == -1) { + ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_errno, "aio_return() failed"); + + return NGX_ERROR; + } + + ngx_log_debug(ev->log, "aio_write: %d" _ rc); + + return rc; +} diff --git a/src/event/ngx_event_close.c b/src/event/ngx_event_close.c --- a/src/event/ngx_event_close.c +++ b/src/event/ngx_event_close.c @@ -27,7 +27,7 @@ int ngx_event_close_connection(ngx_event ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); if ((rc = ngx_close_socket(c->fd)) == -1) - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, "ngx_event_close: close failed"); c->fd = -1; diff --git a/src/event/ngx_event_recv.c b/src/event/ngx_event_recv.c --- a/src/event/ngx_event_recv.c +++ b/src/event/ngx_event_recv.c @@ -6,7 +6,7 @@ #include #include -int ngx_event_recv_core(ngx_connection_t *c, char *buf, size_t size) +ssize_t ngx_event_recv_core(ngx_connection_t *c, char *buf, size_t size) { int n; ngx_err_t err; @@ -20,9 +20,23 @@ int ngx_event_recv_core(ngx_connection_t #if (HAVE_KQUEUE) ngx_log_debug(c->log, "ngx_event_recv: eof:%d, avail:%d, err:%d" _ c->read->eof _ c->read->available _ c->read->error); -#if !(USE_KQUEUE) - if (ngx_event_type == NGX_KQUEUE_EVENT) #endif + +#if (USE_KQUEUE) + + if (c->read->eof && c->read->available == 0) { + if (c->read->error) { + ngx_log_error(NGX_LOG_ERR, c->log, c->read->error, + "recv() failed"); + return NGX_ERROR; + } + + return 0; + } + +#elif (HAVE_KQUEUE) + + if (ngx_event_type == NGX_KQUEUE_EVENT) { if (c->read->eof && c->read->available == 0) { if (c->read->error) { ngx_log_error(NGX_LOG_ERR, c->log, c->read->error, @@ -32,6 +46,8 @@ int ngx_event_recv_core(ngx_connection_t return 0; } + } + #endif n = ngx_recv(c->fd, buf, size, 0); @@ -48,11 +64,16 @@ int ngx_event_recv_core(ngx_connection_t return NGX_ERROR; } -#if (HAVE_KQUEUE) -#if !(USE_KQUEUE) - if (ngx_event_type == NGX_KQUEUE_EVENT) -#endif +#if (USE_KQUEUE) + + c->read->available -= n; + +#elif (HAVE_KQUEUE) + + if (ngx_event_type == NGX_KQUEUE_EVENT) { c->read->available -= n; + } + #endif return n; diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -15,8 +15,6 @@ int ngx_event_find_timer(void); void ngx_event_expire_timers(ngx_msec_t timer); -extern ngx_event_t *ngx_timer_queue; - ngx_inline static void ngx_event_del_timer(ngx_event_t *ev) { @@ -41,4 +39,4 @@ ngx_inline static void ngx_event_del_tim } -#endif _NGX_EVENT_TIMER_H_INCLUDED_ +#endif /* _NGX_EVENT_TIMER_H_INCLUDED_ */ diff --git a/src/event/ngx_event_write.c b/src/event/ngx_event_write.c --- a/src/event/ngx_event_write.c +++ b/src/event/ngx_event_write.c @@ -11,11 +11,11 @@ #include -ngx_chain_t *ngx_event_write(ngx_connection_t *c, ngx_chain_t *in, - off_t flush) +ngx_chain_t *ngx_event_write(ngx_connection_t *c, ngx_chain_t *in, off_t flush) { - int rc; - char *last; + int rc, i, last; + u_int flags; + char *prev; off_t sent; ngx_iovec_t *iov; ngx_array_t *header, *trailer; @@ -24,6 +24,7 @@ ngx_chain_t *ngx_event_write(ngx_connect ch = in; file = NULL; + last = 0; ngx_test_null(header, ngx_create_array(c->pool, 10, sizeof(ngx_iovec_t)), (ngx_chain_t *) -1); @@ -36,12 +37,12 @@ ngx_chain_t *ngx_event_write(ngx_connect trailer->nelts = 0; if (ch->hunk->type & NGX_HUNK_IN_MEMORY) { - last = NULL; + prev = NULL; iov = NULL; while (ch && (ch->hunk->type & NGX_HUNK_IN_MEMORY)) { - if (last == ch->hunk->pos.mem) { + if (prev == ch->hunk->pos.mem) { iov->ngx_iov_len += ch->hunk->last.mem - ch->hunk->pos.mem; } else { @@ -49,7 +50,11 @@ ngx_chain_t *ngx_event_write(ngx_connect (ngx_chain_t *) -1); iov->ngx_iov_base = ch->hunk->pos.mem; iov->ngx_iov_len = ch->hunk->last.mem - ch->hunk->pos.mem; - last = ch->hunk->last.mem; + prev = ch->hunk->last.mem; + } + + if (ch->hunk->type & NGX_HUNK_LAST) { + last = 1; } ch = ch->next; @@ -59,6 +64,10 @@ ngx_chain_t *ngx_event_write(ngx_connect if (ch && (ch->hunk->type & NGX_HUNK_FILE)) { file = ch->hunk; ch = ch->next; + + if (ch->hunk->type & NGX_HUNK_LAST) { + last = 1; + } } #if (HAVE_MAX_SENDFILE_IOVEC) @@ -68,12 +77,12 @@ ngx_chain_t *ngx_event_write(ngx_connect } else { #endif if (ch && ch->hunk->type & NGX_HUNK_IN_MEMORY) { - last = NULL; + prev = NULL; iov = NULL; while (ch && (ch->hunk->type & NGX_HUNK_IN_MEMORY)) { - if (last == ch->hunk->pos.mem) { + if (prev == ch->hunk->pos.mem) { iov->ngx_iov_len += ch->hunk->last.mem - ch->hunk->pos.mem; @@ -83,7 +92,11 @@ ngx_chain_t *ngx_event_write(ngx_connect iov->ngx_iov_base = ch->hunk->pos.mem; iov->ngx_iov_len = ch->hunk->last.mem - ch->hunk->pos.mem; - last = ch->hunk->last.mem; + prev = ch->hunk->last.mem; + } + + if (ch->hunk->type & NGX_HUNK_LAST) { + last = 1; } ch = ch->next; @@ -91,19 +104,47 @@ ngx_chain_t *ngx_event_write(ngx_connect } if (file) { - rc = ngx_sendfile(c->fd, + flags = ngx_sendfile_flags; +#if (HAVE_SENDFILE_DISCONNECT) + if (last && c->close) { + flags |= HAVE_SENDFILE_DISCONNECT; + } +#endif + rc = ngx_sendfile(c, (ngx_iovec_t *) header->elts, header->nelts, file->file->fd, file->pos.file, (size_t) (file->last.file - file->pos.file), (ngx_iovec_t *) trailer->elts, trailer->nelts, - &sent, c->log); + &sent, flags); + +#if (HAVE_AIO_EVENT) && !(HAVE_IOCP_EVENT) + } else if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + + sent = 0; + rc = NGX_AGAIN; + iov = (ngx_iovec_t *) header->elts; + for (i = 0; i < header->nelts; i++) { + rc = ngx_event_aio_write(c, iov[i].ngx_iov_base, + iov[i].ngx_iov_len); + + if (rc > 0) { + sent += rc; + } else { + break; + } + + if (rc < (int) iov->ngx_iov_len) { + break; + } + } +#endif } else { rc = ngx_sendv(c, (ngx_iovec_t *) header->elts, header->nelts); sent = rc > 0 ? rc: 0; #if (NGX_DEBUG_EVENT_WRITE) - ngx_log_debug(c->log, "sendv: " QD_FMT _ sent); + ngx_log_debug(c->log, "sendv: " OFF_FMT _ sent); #endif } #if (HAVE_MAX_SENDFILE_IOVEC) @@ -118,7 +159,7 @@ ngx_chain_t *ngx_event_write(ngx_connect for (ch = in; ch; ch = ch->next) { #if (NGX_DEBUG_EVENT_WRITE) - ngx_log_debug(c->log, "event write: %x " QX_FMT " " QD_FMT _ + ngx_log_debug(c->log, "event write: %x " QX_FMT " " OFF_FMT _ ch->hunk->type _ ch->hunk->pos.file _ ch->hunk->last.file - ch->hunk->pos.file); @@ -129,7 +170,7 @@ ngx_chain_t *ngx_event_write(ngx_connect ch->hunk->pos.file = ch->hunk->last.file; #if (NGX_DEBUG_EVENT_WRITE) - ngx_log_debug(c->log, "event write: " QX_FMT " 0 " QD_FMT _ + ngx_log_debug(c->log, "event write: " QX_FMT " 0 " OFF_FMT _ ch->hunk->pos.file _ sent); #endif @@ -144,7 +185,7 @@ ngx_chain_t *ngx_event_write(ngx_connect ch->hunk->pos.file += sent; #if (NGX_DEBUG_EVENT_WRITE) - ngx_log_debug(c->log, "event write: " QX_FMT " " QD_FMT _ + ngx_log_debug(c->log, "event write: " QX_FMT " " OFF_FMT _ ch->hunk->pos.file _ ch->hunk->last.file - ch->hunk->pos.file); #endif diff --git a/src/event/ngx_event_wsarecv.c b/src/event/ngx_event_wsarecv.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_wsarecv.c @@ -0,0 +1,97 @@ + +#include + +#include +#include +#include +#include +#include + + +ssize_t ngx_event_wsarecv(ngx_connection_t *c, char *buf, size_t size) +{ + int rc; + u_int flags; + size_t bytes; + ngx_err_t err; + WSABUF wsabuf[1]; + ngx_event_t *ev; + LPWSAOVERLAPPED_COMPLETION_ROUTINE handler; + + ev = c->read; + +/* DEBUG */ bytes = 0; + + if (ev->timedout) { + ngx_set_socket_errno(NGX_ETIMEDOUT); + ngx_log_error(NGX_LOG_ERR, ev->log, 0, "WSARecv() timed out"); + + return NGX_ERROR; + } + + if (ev->ready) { + ev->ready = 0; + +#if (HAVE_IOCP_EVENT) /* iocp */ + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + if (ev->ovlp.error) { + ngx_log_error(NGX_LOG_ERR, c->log, ev->ovlp.error, + "WSARecv() failed"); + return NGX_ERROR; + } + + return ev->available; + } + +#endif + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &ev->ovlp, + &bytes, 0, NULL) == 0) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_CRIT, ev->log, err, + "WSARecv() or WSAGetOverlappedResult() failed"); + + return NGX_ERROR; + } + + return bytes; + } + + ngx_memzero(&ev->ovlp, sizeof(WSAOVERLAPPED)); + wsabuf[0].buf = buf; + wsabuf[0].len = size; + flags = 0; + +#if 0 + handler = ev->handler; +#else + handler = NULL; +#endif + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, + (LPWSAOVERLAPPED) &ev->ovlp, handler); + + ngx_log_debug(ev->log, "WSARecv: %d:%d" _ rc _ bytes); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + return NGX_AGAIN; + + } else { + ngx_log_error(NGX_LOG_CRIT, ev->log, err, "WSARecv() failed"); + return NGX_ERROR; + } + } + +#if (HAVE_IOCP_EVENT) /* iocp */ + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + return NGX_AGAIN; + } + +#endif + + return bytes; +} diff --git a/src/http/modules/ngx_http_event_proxy_handler.c b/src/http/modules/ngx_http_event_proxy_handler.c --- a/src/http/modules/ngx_http_event_proxy_handler.c +++ b/src/http/modules/ngx_http_event_proxy_handler.c @@ -6,6 +6,7 @@ #include #include #include +#include #include ngx_http_module_t ngx_http_proxy_module_ctx; @@ -30,6 +31,9 @@ static int ngx_read_http_proxy_status_li static char conn_close[] = "Connection: close" CRLF; +/* AF_INET only */ + + int ngx_http_proxy_handler(ngx_http_request_t *r) { struct sockaddr_in addr; @@ -56,7 +60,7 @@ int ngx_http_proxy_handler(ngx_http_requ addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(9000); - ngx_http_proxy_connect(r, &addr, "connecting to 127.0.0.1:9000"); + return ngx_http_proxy_connect(r, &addr, "connecting to 127.0.0.1:9000"); } @@ -151,7 +155,7 @@ static int ngx_http_proxy_connect(ngx_ht s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0); if (s == -1) { - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_socket_n " failed"); return NGX_ERROR; } @@ -164,7 +168,7 @@ static int ngx_http_proxy_connect(ngx_ht "setsockopt(SO_RCVBUF) failed"); if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -178,7 +182,7 @@ static int ngx_http_proxy_connect(ngx_ht ngx_nonblocking_n " failed"); if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -190,10 +194,10 @@ static int ngx_http_proxy_connect(ngx_ht if (rc == -1) { err = ngx_socket_errno; if (err != NGX_EINPROGRESS) { - ngx_log_error(NGX_LOG_ERR, c->log, err, "connect() failed"); + ngx_log_error(NGX_LOG_CRIT, c->log, err, "connect() failed"); if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ERR, c->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } @@ -271,7 +275,7 @@ static int ngx_http_proxy_send_request(n static int ngx_http_proxy_read_response_header(ngx_event_t *ev) { - int n, rc; + int n; ngx_hunk_t **ph; ngx_connection_t *c; ngx_http_request_t *r; @@ -298,13 +302,12 @@ static int ngx_http_proxy_read_response_ ngx_palloc(r->pool, sizeof(ngx_http_proxy_headers_in_t)), NGX_ERROR); - ngx_test_null(p->hunks, - ngx_create_array(r->pool, - /* STUB */ 10 /**/, - sizeof(ngx_hunk_t *)), - NGX_ERROR); + ngx_init_array(p->hunks, r->pool, + /* STUB */ 10 /**/, + sizeof(ngx_hunk_t *), + NGX_ERROR); - ngx_test_null(ph, ngx_push_array(p->hunks), NGX_ERROR); + ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); *ph = p->header_in; p->state_handler = ngx_http_proxy_process_status_line; @@ -387,51 +390,64 @@ static int ngx_http_proxy_process_status /* STUB */ return NGX_ERROR; } +#if 0 static int ngx_http_proxy_process_response_header(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) { + return NGX_OK; } +#endif static int ngx_http_proxy_read_response_body(ngx_event_t *ev) { - int n; - size_t left; + int n; + char *buf; + size_t left, size; ngx_hunk_t *h, **ph; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; - if (ev->timedout) + if (ev->timedout) { return NGX_ERROR; + } c = (ngx_connection_t *) ev->data; r = (ngx_http_request_t *) c->data; p = (ngx_http_proxy_ctx_t *) ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); - left = 0; + if (p->hunks.nelts > 0) { + h = ((ngx_hunk_t **) p->hunks.elts)[p->hunks.nelts - 1]; + left = h->end - h->last.mem; - if (p->hunks->nelts > 0) { - h = ((ngx_hunk_t **) p->hunks->elts)[p->hunks->nelts - 1]; - left = h->end - h->last.mem; + } else { + h = NULL; + left = 0; } do { -#if (HAVE_KQUEUE) -#if !(USE_KQUEUE) +#if (USE_KQUEUE) + + /* do not allocate new block if there is EOF */ + if (ev->eof && ev->available == 0) { + left = 1; + } + +#elif (HAVE_KQUEUE) + if (ngx_event_type == NGX_KQUEUE_EVENT) { -#endif /* do not allocate new block if there is EOF */ if (ev->eof && ev->available == 0) { left = 1; } -#if !(USE_KQUEUE) } + #endif -#endif + if (left == 0) { - ngx_test_null(ph, ngx_push_array(p->hunks), NGX_ERROR); + ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); ngx_test_null(h, ngx_create_temp_hunk(r->pool, /* STUB */ 4096 /**/, 0, 0), @@ -441,7 +457,16 @@ static int ngx_http_proxy_read_response_ *ph = h; } - n = ngx_event_recv(c, h->last.mem, h->end - h->last.mem); + if (h != NULL) { + buf = h->last.mem; + size = h->end - h->last.mem; + + } else { + buf = (char *) &buf; + size = 0; + } + + n = ngx_event_recv(c, buf, size); ngx_log_debug(c->log, "READ:%d" _ n); @@ -492,14 +517,14 @@ static int ngx_http_proxy_write_to_clien ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); do { - h = ((ngx_hunk_t **) p->hunks->elts)[p->hunk_n]; + h = ((ngx_hunk_t **) p->hunks.elts)[p->hunk_n]; rc = ngx_http_output_filter(r, h); if (rc != NGX_OK) { return rc; } - if (p->hunk_n >= p->hunks->nelts) { + if (p->hunk_n >= p->hunks.nelts) { break; } @@ -534,8 +559,10 @@ static int ngx_read_http_proxy_status_li while (p < ctx->header_in->last.mem && state < sw_done) { ch = *p++; +#if 0 fprintf(stderr, "state: %d, pos: %x, end: %x, char: '%c', status: %d\n", - state, p, ctx->header_in->last.mem, ch, ctx->status); + state, p, ctx->header_in->last.mem, ch, ctx->status); +#endif switch (state) { diff --git a/src/http/modules/ngx_http_event_proxy_handler.h b/src/http/modules/ngx_http_event_proxy_handler.h --- a/src/http/modules/ngx_http_event_proxy_handler.h +++ b/src/http/modules/ngx_http_event_proxy_handler.h @@ -20,7 +20,7 @@ struct ngx_http_proxy_ctx_s { ngx_chain_t *out; int last_hunk; - ngx_array_t *hunks; + ngx_array_t hunks; int hunk_n; diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c --- a/src/http/modules/ngx_http_index_handler.c +++ b/src/http/modules/ngx_http_index_handler.c @@ -244,7 +244,9 @@ static void *ngx_http_index_create_conf( /* STUB */ static char *ngx_http_index_merge_conf(ngx_pool_t *p, void *parent, void *child) { +#if 0 ngx_http_index_conf_t *prev = (ngx_http_index_conf_t *) parent; +#endif ngx_http_index_conf_t *conf = (ngx_http_index_conf_t *) child; ngx_str_t *index; diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c --- a/src/http/modules/ngx_http_static_handler.c +++ b/src/http/modules/ngx_http_static_handler.c @@ -1,9 +1,11 @@ #include + #include #include #include #include +#include ngx_http_module_t ngx_http_static_module; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -10,6 +10,7 @@ #include +static void ngx_http_init_filters(ngx_pool_t *pool, ngx_module_t **modules); static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy); @@ -59,6 +60,39 @@ ngx_module_t ngx_http_module = { }; + +static void ngx_http_init_filters(ngx_pool_t *pool, ngx_module_t **modules) +{ + int i; + ngx_http_module_t *module; + int (*ohf)(ngx_http_request_t *r); + int (*obf)(ngx_http_request_t *r, ngx_chain_t *ch); + + ohf = NULL; + obf = NULL; + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_HTTP_MODULE_TYPE) { + continue; + } + + module = (ngx_http_module_t *) modules[i]->ctx; + + if (module->output_header_filter) { + module->next_output_header_filter = ohf; + ohf = module->output_header_filter; + } + + if (module->output_body_filter) { + module->next_output_body_filter = obf; + obf = module->output_body_filter; + } + } + + ngx_http_top_header_filter = ohf; +} + + static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy) { int i, s, l, p, a, n, start; @@ -442,9 +476,13 @@ int ngx_http_init(ngx_pool_t *pool, ngx_ ls->family = AF_INET; ls->type = SOCK_STREAM; ls->protocol = IPPROTO_IP; + #if (NGX_OVERLAPPED) ls->flags = WSA_FLAG_OVERLAPPED; +#else + ls->nonblocking = 1; #endif + ls->sockaddr = (struct sockaddr *) &addr; ls->socklen = sizeof(struct sockaddr_in); ls->addr = offsetof(struct sockaddr_in, sin_addr); @@ -452,7 +490,6 @@ int ngx_http_init(ngx_pool_t *pool, ngx_ ls->addr_text.data = addr_text; ls->backlog = -1; ls->post_accept_timeout = 10000; - ls->nonblocking = 1; ls->handler = ngx_http_init_connection; ls->server = &ngx_http_server; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -67,14 +67,14 @@ typedef struct { typedef struct { - int len; - char *data; - int offset; + size_t len; + char *data; + int offset; } ngx_http_header_t; typedef struct { - int host_name_len; + size_t host_name_len; ngx_table_elt_t *host; ngx_table_elt_t *connection; @@ -240,12 +240,22 @@ int ngx_http_init(ngx_pool_t *pool, ngx_ /**/ int ngx_http_init_connection(ngx_connection_t *c); +int ngx_read_http_request_line(ngx_http_request_t *r); +int ngx_read_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h); +int ngx_http_handler(ngx_http_request_t *r); + + +int ngx_http_send_header(ngx_http_request_t *r); +int ngx_http_special_response(ngx_http_request_t *r, int error); + + +time_t ngx_http_parse_time(char *value, size_t len); +size_t ngx_http_get_time(char *buf, time_t t); int ngx_http_discard_body(ngx_http_request_t *r); -int ngx_http_special_response(ngx_http_request_t *r, int error); extern int ngx_max_module; @@ -269,5 +279,9 @@ extern ngx_array_t ngx_http_index_handl extern ngx_http_module_t *ngx_http_modules[]; +/* STUB */ +int ngx_http_log_handler(ngx_http_request_t *r); +/**/ + #endif /* _NGX_HTTP_H_INCLUDED_ */ diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -32,4 +32,4 @@ extern void **ngx_srv_conf; extern void **ngx_loc_conf; -#endif _NGX_HTTP_CONFIG_H_INCLUDED_ +#endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */ diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -10,13 +10,9 @@ #include #include -#if 0 -#include +/* STUB for r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY; */ #include -#endif -/* STUB */ -#include int ngx_http_static_handler(ngx_http_request_t *r); int ngx_http_proxy_handler(ngx_http_request_t *r); /**/ @@ -104,8 +100,13 @@ int ngx_http_handler(ngx_http_request_t ngx_http_server_name_t *name; r->connection->unexpected_eof = 0; - r->lingering_close = 1; - r->keepalive = 1; + + r->lingering_close = 0; + r->keepalive = 0; + +#if 0 + r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY; +#endif ngx_log_debug(r->connection->log, "servers: %0x" _ r->connection->servers); @@ -163,12 +164,6 @@ ngx_log_debug(r->connection->log, "cxt: ngx_log_debug(r->connection->log, "srv_conf: %0x" _ r->srv_conf); ngx_log_debug(r->connection->log, "loc_conf: %0x" _ r->loc_conf); - -#if 1 - r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY; -#endif - - /* run translation phase */ for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_HTTP_MODULE_TYPE) { @@ -496,8 +491,13 @@ int ngx_http_close_request(ngx_http_requ ngx_log_debug(r->connection->log, "http close"); - ngx_del_timer(r->connection->read); - ngx_del_timer(r->connection->write); + if (r->connection->read->timer_set) { + ngx_del_timer(r->connection->read); + } + + if (r->connection->write->timer_set) { + ngx_del_timer(r->connection->write); + } return NGX_DONE; } @@ -669,73 +669,6 @@ static char *ngx_location_block(ngx_conf } -int ngx_http_config_modules(ngx_pool_t *pool, ngx_module_t **modules) -{ - int i; - ngx_http_module_t *module; - - for (i = 0; modules[i]; i++) { - if (modules[i]->type != NGX_HTTP_MODULE_TYPE) { - continue; - } - - module = (ngx_http_module_t *) modules[i]->ctx; - module->index = i; - } - - ngx_http_max_module = i; - -#if 0 - ngx_test_null(ngx_srv_conf, - ngx_pcalloc(pool, sizeof(void *) * ngx_http_max_module), - NGX_ERROR); - ngx_test_null(ngx_loc_conf, - ngx_pcalloc(pool, sizeof(void *) * ngx_http_max_module), - NGX_ERROR); - - for (i = 0; modules[i]; i++) { - if (modules[i]->create_srv_conf) - ngx_srv_conf[i] = modules[i]->create_srv_conf(pool); - - if (modules[i]->create_loc_conf) - ngx_loc_conf[i] = modules[i]->create_loc_conf(pool); - } -#endif -} - - -void ngx_http_init_filters(ngx_pool_t *pool, ngx_module_t **modules) -{ - int i; - ngx_http_module_t *module; - int (*ohf)(ngx_http_request_t *r); - int (*obf)(ngx_http_request_t *r, ngx_chain_t *ch); - - ohf = NULL; - obf = NULL; - - for (i = 0; modules[i]; i++) { - if (modules[i]->type != NGX_HTTP_MODULE_TYPE) { - continue; - } - - module = (ngx_http_module_t *) modules[i]->ctx; - - if (module->output_header_filter) { - module->next_output_header_filter = ohf; - ohf = module->output_header_filter; - } - - if (module->output_body_filter) { - module->next_output_body_filter = obf; - obf = module->output_body_filter; - } - } - - ngx_http_top_header_filter = ohf; -} - - static void *ngx_http_core_create_srv_conf(ngx_pool_t *pool) { ngx_http_core_srv_conf_t *scf, **cf; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -8,7 +8,7 @@ typedef struct { - int addr; + u_int32_t addr; int port; int family; int flags; /* 'default' */ @@ -85,6 +85,7 @@ extern int ngx_http_max_module; int ngx_http_core_translate_handler(ngx_http_request_t *r); +int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri); int ngx_http_error(ngx_http_request_t *r, int error); int ngx_http_close_request(ngx_http_request_t *r); diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_event.c --- a/src/http/ngx_http_event.c +++ b/src/http/ngx_http_event.c @@ -15,9 +15,8 @@ #include #include #include - +#include -int ngx_http_init_connection(ngx_connection_t *c); static int ngx_http_init_request(ngx_event_t *ev); static int ngx_http_process_request_header(ngx_event_t *ev); @@ -89,9 +88,11 @@ int ngx_http_init_connection(ngx_connect c->log->handler = ngx_http_log_error; #if (HAVE_DEFERRED_ACCEPT) + if (ev->ready) { return ngx_http_init_request(ev); } + #endif ngx_add_timer(ev, c->post_accept_timeout); @@ -103,26 +104,34 @@ int ngx_http_init_connection(ngx_connect #else -#if (HAVE_CLEAR_EVENT) +#if (HAVE_CLEAR_EVENT) /* kqueue */ + if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT); } + #endif -#if (HAVE_EDGE_EVENT) +#if (HAVE_EDGE_EVENT) /* epoll */ + if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { if (ngx_add_event(ev, NGX_READ_EVENT, NGX_EDGE_EVENT) == NGX_ERROR) { return NGX_ERROR; } return ngx_http_init_request(ev); } + #endif -#if (HAVE_AIO_EVENT) +#if (HAVE_AIO_EVENT) /* aio, iocp */ + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { return ngx_http_init_request(ev); } -#endif + +#endif /* HAVE_AIO_EVENT */ + + /* select, poll, /dev/poll */ return ngx_add_event(ev, NGX_READ_EVENT, NGX_LEVEL_EVENT); @@ -182,7 +191,7 @@ static int ngx_http_init_request(ngx_eve static int ngx_http_process_request_header(ngx_event_t *ev) { - int n, rc; + int n, rc; ngx_connection_t *c; ngx_http_request_t *r; @@ -191,55 +200,64 @@ static int ngx_http_process_request_head ngx_log_debug(ev->log, "http process request"); - if (r->header_read) { - r->header_read = 0; - ngx_log_debug(ev->log, "http preread %d" _ - r->header_in->last.mem - r->header_in->pos.mem); +#if (HAVE_AIO_EVENT) + do { +#endif - } else { - n = ngx_event_recv(c, r->header_in->last.mem, - r->header_in->end - r->header_in->last.mem); + if (r->header_read) { + r->header_read = 0; + ngx_log_debug(ev->log, "http preread %d" _ + r->header_in->last.mem - r->header_in->pos.mem); + + } else { + n = ngx_event_recv(c, r->header_in->last.mem, + r->header_in->end - r->header_in->last.mem); + + if (n == NGX_AGAIN) { + if (!r->header_timeout_set) { - if (n == NGX_AGAIN) { - if (!r->header_timeout_set) { + if (ev->timer_set) { + ngx_del_timer(ev); + } else { + ev->timer_set = 1; + } + + ngx_add_timer(ev, ngx_http_client_header_timeout); + r->header_timeout_set = 1; + } + return NGX_AGAIN; + } - if (ev->timer_set) { - ngx_del_timer(ev); - } else { - ev->timer_set = 1; - } + if (n == NGX_ERROR) + return ngx_http_close_request(r); + + ngx_log_debug(ev->log, "http read %d" _ n); - ngx_add_timer(ev, ngx_http_client_header_timeout); - r->header_timeout_set = 1; + if (n == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client has prematurely closed connection"); + return ngx_http_close_request(r); } - return NGX_AGAIN; + + r->header_in->last.mem += n; } - if (n == NGX_ERROR) - return ngx_http_close_request(r); - - ngx_log_debug(ev->log, "http read %d" _ n); + /* state_handlers are called in following order: + ngx_http_process_request_line(r) + ngx_http_process_request_headers(r) */ - if (n == 0) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client has prematurely closed connection"); - return ngx_http_close_request(r); - } + do { + rc = (r->state_handler)(r); - r->header_in->last.mem += n; - } - - /* state_handlers are called in following order: - ngx_http_process_request_line(r) - ngx_http_process_request_headers(r) */ + if (rc == NGX_ERROR) + return rc; - do { - rc = (r->state_handler)(r); + } while (rc == NGX_AGAIN + && r->header_in->pos.mem < r->header_in->last.mem); - if (rc == NGX_ERROR) - return rc; - - } while (rc == NGX_AGAIN && r->header_in->pos.mem < r->header_in->last.mem); +#if (HAVE_AIO_EVENT) /* aio, iocp */ + } while (rc == NGX_AGAIN && ngx_event_flags & NGX_HAVE_AIO_EVENT); +#endif if (rc == NGX_OK) { /* HTTP header done */ @@ -345,7 +363,8 @@ static int ngx_http_process_request_line static int ngx_http_process_request_headers(ngx_http_request_t *r) { - int rc, len; + int rc; + size_t len; ngx_http_log_ctx_t *ctx; for ( ;; ) { @@ -432,7 +451,7 @@ static int ngx_http_process_request_head static int ngx_http_event_request_handler(ngx_http_request_t *r) { - int rc; + int rc, event; ngx_msec_t timeout; ngx_event_t *rev, *wev; @@ -453,20 +472,11 @@ static int ngx_http_event_request_handle if (rc == NGX_WAITING) return rc; - /* handler has done its work but transfer is not completed */ + /* handler has done its work but transfer is still not completed */ if (rc == NGX_AGAIN) { -#if (HAVE_CLEAR_EVENT) - if (ngx_add_event(wev, NGX_WRITE_EVENT, - NGX_CLEAR_EVENT) == NGX_ERROR) { -#else - if (ngx_add_event(wev, NGX_WRITE_EVENT, - NGX_ONESHOT_EVENT) == NGX_ERROR) { -#endif - return ngx_http_close_request(r); - } if (r->connection->sent > 0) { - ngx_log_debug(r->connection->log, "sent: " QD_FMT _ + ngx_log_debug(r->connection->log, "sent: " OFF_FMT _ r->connection->sent); timeout = (ngx_msec_t) (r->connection->sent * 10); ngx_log_debug(r->connection->log, "timeout: %d" _ timeout); @@ -477,7 +487,67 @@ static int ngx_http_event_request_handle } wev->event_handler = ngx_http_writer; + +#if (USE_KQUEUE) + + if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) { + return ngx_http_close_request(r); + } + return rc; + +#else + +#if (HAVE_AIO_EVENT) /* aio, iocp */ + + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + return rc; + } + +#endif + +#if (HAVE_CLEAR_EVENT) /* kqueue */ + + if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { + event = NGX_CLEAR_EVENT; + + } else { + event = NGX_ONESHOT_EVENT; + } + +#elif (HAVE_EDGE_EVENT) /* epoll */ + + if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { + event = NGX_EDGE_EVENT; + + } else { + event = NGX_ONESHOT_EVENT; + } + +#elif (HAVE_DEVPOLL_EVENT) /* /dev/poll */ + + if (ngx_event_flags & NGX_HAVE_LEVEL_EVENT) { + event = NGX_LEVEL_EVENT; + + } else { + event = NGX_ONESHOT_EVENT; + } + +#else /* select, poll */ + + event = NGX_ONESHOT_EVENT; + +#endif + + if (ngx_add_event(wev, NGX_WRITE_EVENT, event) == NGX_ERROR) { + return ngx_http_close_request(r); + } + + return rc; + + +#endif /* USE_KQUEUE */ + } if (rc == NGX_ERROR) { @@ -501,10 +571,13 @@ static int ngx_http_event_request_handle /* keepalive */ - ngx_http_close_request(r); r->connection->buffer->pos.mem = r->connection->buffer->last.mem = r->connection->buffer->start; rev->event_handler = ngx_http_keepalive_handler; + + ngx_http_close_request(r); + + return NGX_OK; } @@ -532,7 +605,7 @@ static int ngx_http_writer(ngx_event_t * timeout = (ngx_msec_t) (c->sent * conf->send_timeout); - ngx_log_debug(ev->log, "sent: " QD_FMT _ c->sent); + ngx_log_debug(ev->log, "sent: " OFF_FMT _ c->sent); ngx_log_debug(ev->log, "timeout: %d" _ timeout); if (ev->timer_set) { @@ -544,9 +617,11 @@ static int ngx_http_writer(ngx_event_t * ngx_add_timer(ev, timeout); } + /* TODO: /dev/poll, epoll, aio_write */ + if (ev->oneshot) - if (ngx_add_event(ev, NGX_WRITE_EVENT, - NGX_ONESHOT_EVENT) == NGX_ERROR) { + if (ngx_add_event(ev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT) + == NGX_ERROR) { return ngx_http_close_request(r); } @@ -571,9 +646,12 @@ static int ngx_http_writer(ngx_event_t * /* keepalive */ - ngx_http_close_request(r); c->buffer->pos.mem = c->buffer->last.mem = c->buffer->start; c->read->event_handler = ngx_http_keepalive_handler; + + ngx_http_close_request(r); + + return NGX_OK; } @@ -581,8 +659,37 @@ static int ngx_http_block_read(ngx_event { ngx_log_debug(ev->log, "http read blocked"); + /* aio does not call this handler */ + +#if (USE_KQUEUE) + + return NGX_OK; + +#else + +#if (HAVE_CLEAR_EVENT) /* kqueue */ + + if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { + return NGX_OK; + } + +#endif + +#if (HAVE_EDGE_EVENT) /* epoll */ + + if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { + return NGX_OK; + } + +#endif + + /* select, poll, /dev/poll */ + ev->blocked = 1; + return ngx_del_event(ev, NGX_READ_EVENT, 0); + +#endif /* USE_KQUEUE */ } @@ -599,8 +706,11 @@ int ngx_http_discard_body(ngx_http_reque ev->timer_set = 0; } - if (r->client_content_length) + if (r->client_content_length) { ev->event_handler = ngx_http_read_discarded_body; + /* if blocked - read */ + /* else add timer */ + } return NGX_OK; } @@ -752,7 +862,7 @@ static int ngx_http_lingering_close_hand ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx); if (r->discarded_buffer == NULL) { - if (r->header_in->end - r->header_in->last.mem + if ((size_t)(r->header_in->end - r->header_in->last.mem) >= lcf->discarded_buffer_size) { r->discarded_buffer = r->header_in->last.mem; @@ -789,8 +899,6 @@ static int ngx_http_lingering_close_hand static int ngx_http_close_connection(ngx_event_t *ev) { - ngx_connection_t *c = (ngx_connection_t *) ev->data; - return ngx_event_close_connection(ev); } diff --git a/src/http/ngx_http_output_filter.c b/src/http/ngx_http_output_filter.c --- a/src/http/ngx_http_output_filter.c +++ b/src/http/ngx_http_output_filter.c @@ -60,6 +60,7 @@ ngx_module_t ngx_http_output_filter_mod int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) { int rc, once; + u_int flags; size_t size; ngx_chain_t *ce; ngx_http_output_filter_ctx_t *ctx; @@ -272,11 +273,10 @@ int ngx_http_output_filter(ngx_http_requ static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src) { - size_t size; - ssize_t n; + ssize_t n, size; size = src->last.mem - src->pos.mem; - if (size > dst->end - dst->pos.mem) { + if (size > (dst->end - dst->pos.mem)) { size = dst->end - dst->pos.mem; } @@ -337,7 +337,7 @@ static char *ngx_http_output_filter_merg ngx_http_output_filter_conf_t *conf = (ngx_http_output_filter_conf_t *) child; - ngx_conf_merge(conf->hunk_size, prev->hunk_size, 32768); + ngx_conf_size_merge(conf->hunk_size, prev->hunk_size, 32768); return NULL; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -304,11 +304,6 @@ printf("\nstate: %d, pos: %x, end: %x, c return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - -#if (NGX_SUPPRESS_WARN) - case sw_done: - break; -#endif } } @@ -495,14 +490,6 @@ printf("\nstate: %d, pos: %x, end: %x, c return NGX_HTTP_PARSE_INVALID_HEADER; } break; - -#if (NGX_SUPPRESS_WARN) - case sw_done: - break; - - case sw_header_done: - break; -#endif } } diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -5,6 +5,8 @@ #include #include #include +#include + static char error_tail[] = "
" NGINX_VER "
" CRLF @@ -12,6 +14,7 @@ static char error_tail[] = "" CRLF ; + static char error_400_page[] = "" CRLF "400 Bad Request" CRLF @@ -19,6 +22,7 @@ static char error_400_page[] = "

400 Bad Request

" CRLF ; + static char error_403_page[] = "" CRLF "403 Forbidden" CRLF @@ -26,6 +30,7 @@ static char error_403_page[] = "

403 Forbidden

" CRLF ; + static char error_404_page[] = "" CRLF "404 Not Found" CRLF @@ -33,6 +38,7 @@ static char error_404_page[] = "

404 Not Found

" CRLF ; + static char error_500_page[] = "" CRLF "500 Internal Server Error" CRLF @@ -56,9 +62,10 @@ static ngx_str_t error_pages[] = { { sizeof(error_500_page) - 1, error_500_page } }; + int ngx_http_special_response(ngx_http_request_t *r, int error) { - int rc, err, len; + int err, len; ngx_hunk_t *message, *tail; len = 0; @@ -80,26 +87,29 @@ int ngx_http_special_response(ngx_http_r r->headers_out.content_length = error_pages[err].len + len + sizeof(error_tail); - ngx_http_send_header(r); + if (ngx_http_send_header(r) == NGX_ERROR) { + return NGX_ERROR; + } - if (error_pages[err].len == 0) + if (error_pages[err].len == 0) { return NGX_OK; + } - ngx_test_null(message, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), - NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_test_null(message, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); message->type = NGX_HUNK_MEMORY; message->pos.mem = error_pages[err].data; message->last.mem = error_pages[err].data + error_pages[err].len; - rc = ngx_http_output_filter(r, message); + if (ngx_http_output_filter(r, message) == NGX_ERROR) { + return NGX_ERROR; + } - ngx_test_null(tail, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), - NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_test_null(tail, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); tail->type = NGX_HUNK_MEMORY|NGX_HUNK_LAST; tail->pos.mem = error_tail; tail->last.mem = error_tail + sizeof(error_tail); - rc = ngx_http_output_filter(r, tail); + return ngx_http_output_filter(r, tail); } diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c --- a/src/http/ngx_http_write_filter.c +++ b/src/http/ngx_http_write_filter.c @@ -171,7 +171,7 @@ static char *ngx_http_write_filter_merge ngx_http_write_filter_conf_t *conf = (ngx_http_write_filter_conf_t *) child; - ngx_conf_merge(conf->buffer_output, prev->buffer_output, 1460); + ngx_conf_size_merge(conf->buffer_output, prev->buffer_output, 1460); return NULL; } diff --git a/src/os/unix/freebsd/ngx_sendfile.c b/src/os/unix/freebsd/ngx_sendfile.c --- a/src/os/unix/freebsd/ngx_sendfile.c +++ b/src/os/unix/freebsd/ngx_sendfile.c @@ -5,25 +5,25 @@ #include #include -#include #include #include #include +#include #include #include /* CHECK: check sent if errno == EINTR then should return right sent. + EINTR should not occur according to man. */ -int ngx_sendfile(ngx_socket_t s, +int ngx_sendfile(ngx_connection_t *c, ngx_iovec_t *headers, int hdr_cnt, ngx_fd_t fd, off_t offset, size_t nbytes, ngx_iovec_t *trailers, int trl_cnt, - off_t *sent, - ngx_log_t *log) + off_t *sent, u_int flags) { int rc, i; ngx_err_t err; @@ -35,26 +35,29 @@ int ngx_sendfile(ngx_socket_t s, hdtr.trl_cnt = trl_cnt; #if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG) - for (i = 0; i < hdr_cnt; i++) + for (i = 0; i < hdr_cnt; i++) { nbytes += headers[i].iov_len; + } #endif - rc = sendfile(fd, s, offset, nbytes, &hdtr, sent, 0); + rc = sendfile(fd, c->fd, offset, nbytes, &hdtr, sent, flags); if (rc == -1) { - err = ngx_socket_errno; + err = ngx_errno; if (err != NGX_EAGAIN && err != NGX_EINTR) { - ngx_log_error(NGX_LOG_ERR, log, err, - "ngx_sendfile: sendfile failed"); + ngx_log_error(NGX_LOG_ERR, c->log, err, "sendfile failed"); + return NGX_ERROR; } else { - ngx_log_error(NGX_LOG_INFO, log, err, - "ngx_sendfile: sendfile sent only %qd bytes", *sent); + ngx_log_error(NGX_LOG_INFO, c->log, err, + "sendfile sent only %qd bytes", *sent); + + return NGX_AGAIN; } } - ngx_log_debug(log, "ngx_sendfile: %d, @%qd %qd:%d" _ + ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _ rc _ offset _ *sent _ nbytes); return NGX_OK; diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -15,6 +15,7 @@ typedef int ngx_err_t; #define NGX_EINPROGRESS EINPROGRESS #define NGX_EADDRINUSE EADDRINUSE #define NGX_ETIMEDOUT ETIMEDOUT +#define NGX_ECANCELED ECANCELED #define ngx_errno errno #define ngx_socket_errno errno diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_socket.c @@ -0,0 +1,26 @@ + +#include + + +/* ioctl(FIONBIO) set blocking mode with one syscall only while + fcntl(F_SETFL, ~O_NONBLOCK) need to know previous state + using fcntl(F_GETFL). + On FreeBSD both are syscall */ + +#ifdef __FreeBSD__ + +int ngx_nonblocking(ngx_socket_t s) +{ + unsigned long nb = 1; + + return ioctl(s, FIONBIO, &nb); +} + +int ngx_blocking(ngx_socket_t s) +{ + unsigned long nb = 0; + + return ioctl(s, FIONBIO, &nb); +} + +#endif diff --git a/src/os/unix/ngx_socket.h b/src/os/unix/ngx_socket.h --- a/src/os/unix/ngx_socket.h +++ b/src/os/unix/ngx_socket.h @@ -4,6 +4,11 @@ #include +#ifdef __FreeBSD__ +#include +#endif + + #define NGX_WRITE_SHUTDOWN SHUT_WR typedef int ngx_socket_t; @@ -11,9 +16,23 @@ typedef int ngx_socket_t; #define ngx_socket(af, type, proto, flags) socket(af, type, proto) #define ngx_socket_n "socket()" + +#ifdef __FreeBSD__ + +int ngx_nonblocking(ngx_socket_t s); +int ngx_blocking(ngx_socket_t s); + +#define ngx_nonblocking_n "ioctl(FIONBIO)" +#define ngx_blocking_n "ioctl(!FIONBIO)" + +#else + #define ngx_nonblocking(s) fcntl(s, F_SETFL, O_NONBLOCK) #define ngx_nonblocking_n "fcntl(O_NONBLOCK)" +#endif + + #define ngx_shutdown_socket shutdown #define ngx_shutdown_socket_n "shutdown()" diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h --- a/src/os/unix/ngx_time.h +++ b/src/os/unix/ngx_time.h @@ -5,7 +5,7 @@ #include typedef u_int ngx_msec_t; -#define NGX_MAX_MSEC ~0 +#define NGX_MAX_MSEC (u_int) ~0 typedef struct tm ngx_tm_t; diff --git a/src/os/win32/ngx_sendfile.c b/src/os/win32/ngx_sendfile.c --- a/src/os/win32/ngx_sendfile.c +++ b/src/os/win32/ngx_sendfile.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -17,18 +18,51 @@ #if (HAVE_WIN32_TRANSMITFILE) -int ngx_sendfile(ngx_socket_t s, +int ngx_sendfile(ngx_connection_t *c, ngx_iovec_t *headers, int hdr_cnt, ngx_fd_t fd, off_t offset, size_t nbytes, ngx_iovec_t *trailers, int trl_cnt, - off_t *sent, - ngx_log_t *log) + off_t *sent, u_int flags) { int tfrc, rc; ngx_err_t tf_err, err; OVERLAPPED olp; TRANSMIT_FILE_BUFFERS tfb, *ptfb; +#if 0 + ev = c->write; + + if (ev->timedout) { + ngx_set_socket_errno(NGX_ETIMEDOUT); + ngx_log_error(NGX_LOG_ERR, ev->log, 0, "TransmitFile() timed out"); + + return NGX_ERROR; + } + + if (ev->ready) { + ev->ready = 0; + +#if (HAVE_IOCP_EVENT) /* iocp */ + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + if (ev->ovlp.error) { + ngx_log_error(NGX_LOG_ERR, ev->log, 0, "TransmitFile() failed"); + return NGX_ERROR; + } + + return ev->available; + } + } + +#endif + + /* TODO: WSAGetOverlappedResult stuff */ + + } + +#endif + + tf_err = 0; err = 0; @@ -49,40 +83,54 @@ int ngx_sendfile(ngx_socket_t s, ptfb = NULL; } -#if 1 - tfrc = TransmitFile(s, fd, nbytes, 0, &olp, ptfb, 0); -#else - tfrc = TransmitFile(s, fd, nbytes, 0, NULL, ptfb, 0); +#if 0 + flags = TF_DISCONNECT|TF_REUSE_SOCKET; #endif - if (tfrc == 0) + tfrc = TransmitFile(c->fd, fd, nbytes, 0, &olp, ptfb, flags); + +#if 0 +#if 1 + tfrc = TransmitFile(c->fd, fd, nbytes, 0, &olp, ptfb, 0); +#else + tfrc = TransmitFile(c->fd, fd, nbytes, 0, NULL, ptfb, 0); +#endif +#endif + + if (tfrc == 0) { tf_err = ngx_socket_errno; + ngx_log_error(NGX_LOG_NOTICE, c->log, tf_err, + "ngx_sendfile: TransmitFile failed"); + if (tf_err == WSA_IO_PENDING) { + return NGX_AGAIN; + } + } /* set sent */ #if 0 - rc = WSAGetOverlappedResult(s, &olp, (unsigned long *) sent, 0, NULL); + rc = WSAGetOverlappedResult(c->fd, &olp, (unsigned long *) sent, 0, NULL); #else *sent = olp.InternalHigh; rc = 1; #endif - ngx_log_debug(log, "ngx_sendfile: %d, @%I64d %I64d:%d" _ + ngx_log_debug(c->log, "TransmitFile: %d, @%I64d %I64d:%d" _ tfrc _ offset _ *sent _ nbytes); if (rc == 0) { err = ngx_socket_errno; - ngx_log_error(NGX_LOG_ERR, log, err, + ngx_log_error(NGX_LOG_ERR, c->log, err, "ngx_sendfile: WSAGetOverlappedResult failed"); } if (tfrc == 0) { if (tf_err != NGX_EAGAIN) { - ngx_log_error(NGX_LOG_ERR, log, tf_err, + ngx_log_error(NGX_LOG_ERR, c->log, tf_err, "ngx_sendfile: TransmitFile failed"); return NGX_ERROR; } - ngx_log_error(NGX_LOG_INFO, log, tf_err, + ngx_log_error(NGX_LOG_INFO, c->log, tf_err, "ngx_sendfile: TransmitFile sent only %I64d bytes", *sent); } diff --git a/src/os/win32/ngx_socket.c b/src/os/win32/ngx_socket.c --- a/src/os/win32/ngx_socket.c +++ b/src/os/win32/ngx_socket.c @@ -1,19 +1,75 @@ + #include +#include #include #include #include -void ngx_init_sockets(ngx_log_t *log) +/* These pointers should be per protocol ? */ +LPFN_ACCEPTEX AcceptEx; +LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockaddrs; +LPFN_TRANSMITFILE TransmitFile; + +static GUID ae_guid = WSAID_ACCEPTEX; +static GUID as_guid = WSAID_GETACCEPTEXSOCKADDRS; +static GUID tf_guid = WSAID_TRANSMITFILE; + + +int ngx_init_sockets(ngx_log_t *log) { + DWORD bytes; + SOCKET s; WSADATA wsd; - if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) + if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "WSAStartup failed"); + return NGX_ERROR; + } + + s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0); + if (s == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " %s falied"); + return NGX_ERROR; + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &ae_guid, sizeof(GUID), + &AcceptEx, sizeof(LPFN_ACCEPTEX), &bytes, NULL, NULL) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "ngx_init_sockets: WSAStartup failed"); + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_ACCEPTEX) failed"); + return NGX_ERROR; + } + + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &as_guid, sizeof(GUID), + &GetAcceptExSockaddrs, sizeof(LPFN_GETACCEPTEXSOCKADDRS), + &bytes, NULL, NULL) == -1) { + + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_ACCEPTEX) failed"); + return NGX_ERROR; + } - /* get AcceptEx(), TransmitFile() functions */ + if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &tf_guid, sizeof(GUID), + &TransmitFile, sizeof(LPFN_TRANSMITFILE), &bytes, + NULL, NULL) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER, " + "WSAID_TRANSMITFILE) failed"); + return NGX_ERROR; + } + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_OK; } int ngx_nonblocking(ngx_socket_t s) diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h --- a/src/os/win32/ngx_socket.h +++ b/src/os/win32/ngx_socket.h @@ -12,14 +12,17 @@ typedef SOCKET ngx_socket_t; typedef int socklen_t; -void ngx_init_sockets(ngx_log_t *log); +int ngx_init_sockets(ngx_log_t *log); #define ngx_socket(af, type, proto, flags) \ WSASocket(af, type, proto, NULL, 0, flags) #define ngx_socket_n "WSASocket()" int ngx_nonblocking(ngx_socket_t s); +int ngx_blocking(ngx_socket_t s); + #define ngx_nonblocking_n "ioctlsocket(FIONBIO)" +#define ngx_blocking_n "ioctlsocket(!FIONBIO)" #define ngx_shutdown_socket shutdown #define ngx_shutdown_socket_n "shutdown()" @@ -28,5 +31,9 @@ int ngx_nonblocking(ngx_socket_t s); #define ngx_close_socket_n "closesocket()" +extern LPFN_ACCEPTEX acceptex; +extern LPFN_GETACCEPTEXSOCKADDRS getacceptexsockaddrs; +extern LPFN_TRANSMITFILE transmitfile; + #endif /* _NGX_SOCKET_H_INCLUDED_ */