# HG changeset patch # User Igor Sysoev # Date 1055345314 0 # Node ID 6dfda4cf5200f19e5d7266dace47e1d97bd23ab4 # Parent 7e86d028d8f00ccaed689db4b0f40ff24770a6b3 nginx-0.0.1-2003-06-11-19:28:34 import diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -2,9 +2,7 @@ #include #include - -#include - +#include #include @@ -61,7 +59,7 @@ int main(int argc, char *const *argv) { ngx_init_array(ngx_listening_sockets, - ngx_pool, 10, sizeof(ngx_listen_t), + ngx_pool, 10, sizeof(ngx_listening_t), 1); ngx_memzero(&conf, sizeof(ngx_conf_t)); @@ -126,10 +124,10 @@ int main(int argc, char *const *argv) static int ngx_open_listening_sockets(ngx_log_t *log) { - int times, failed, reuseaddr, i; - ngx_err_t err; - ngx_socket_t s; - ngx_listen_t *ls; + int times, failed, reuseaddr, i; + ngx_err_t err; + ngx_socket_t s; + ngx_listening_t *ls; reuseaddr = 1; @@ -137,7 +135,8 @@ static int ngx_open_listening_sockets(ng failed = 0; /* for each listening socket */ - ls = (ngx_listen_t *) ngx_listening_sockets.elts; + + ls = ngx_listening_sockets.elts; for (i = 0; i < ngx_listening_sockets.nelts; i++) { if (ls[i].bound) @@ -161,6 +160,19 @@ static int ngx_open_listening_sockets(ng return NGX_ERROR; } +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + return NGX_ERROR; + } +#endif + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuseaddr, sizeof(int)) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 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 @@ -123,8 +123,8 @@ struct ngx_conf_s { } #define ngx_conf_merge_size_value(conf, prev, default) \ - if (conf == (size_t) NGX_CONF_UNSET) { \ - conf = (prev == (size_t) NGX_CONF_UNSET) ? default : prev; \ + if (conf == (ssize_t) NGX_CONF_UNSET) { \ + conf = (prev == (ssize_t) NGX_CONF_UNSET) ? default : prev; \ } #define ngx_conf_merge_str_value(conf, prev, default) \ 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 @@ -1,45 +1,98 @@ #ifndef _NGX_CONNECTION_H_INCLUDED_ #define _NGX_CONNECTION_H_INCLUDED_ + #include #include -#include + + +typedef struct { + ngx_socket_t fd; + + struct sockaddr *sockaddr; + socklen_t socklen; /* size of sockaddr */ + int addr; /* offset to address in sockaddr */ + int addr_text_max_len; + ngx_str_t addr_text; + + int family; + int type; + int protocol; + int flags; /* Winsock2 flags */ + + void (*handler)(ngx_connection_t *c); /* handler of accepted + connection */ + void *ctx; /* ngx_http_conf_ctx_t, for example */ + void *servers; /* array of ngx_http_in_addr_t, for example */ + + ngx_log_t *log; + int backlog; + + int pool_size; + int post_accept_buffer_size; /* should be here because + of the AcceptEx() preread */ + time_t post_accept_timeout; /* should be here because + of the deferred accept */ + + 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 */ +#endif + unsigned shared:1; /* shared between threads or processes */ +#if (HAVE_DEFERRED_ACCEPT) + unsigned deferred_accept:1; +#endif +} ngx_listening_t; struct ngx_connection_s { - ngx_socket_t fd; - void *data; - -#ifdef NGX_EVENT + void *data; ngx_event_t *read; ngx_event_t *write; -#endif + + ngx_socket_t fd; + + ngx_listening_t *listening; off_t sent; +#if 0 void (*handler)(ngx_connection_t *c); +#endif void *ctx; void *servers; + ngx_log_t *log; ngx_pool_t *pool; +#if 0 int pool_size; int family; +#endif + struct sockaddr *sockaddr; socklen_t socklen; + ngx_str_t addr_text; + #if (HAVE_IOCP) struct sockaddr *local_sockaddr; socklen_t local_socklen; - void *listening; #endif + +#if 0 int addr; int addr_text_max_len; - ngx_str_t addr_text; +#endif ngx_hunk_t *buffer; +#if 0 unsigned int post_accept_timeout; +#endif int number; @@ -47,9 +100,15 @@ struct ngx_connection_s { unsigned unexpected_eof:1; unsigned tcp_nopush:1; unsigned tcp_nopush_enabled:1; +#if (HAVE_IOCP) + unsigned accept_context_updated:1; +#endif }; + + + #if 0 cached file int fd; -2 unused, -1 closed (but read or mmaped), >=0 open @@ -84,10 +143,11 @@ typedef struct { #endif + +extern ngx_array_t ngx_listening_sockets; extern ngx_os_io_t ngx_io; - extern ngx_chain_t *(*ngx_write_chain_proc) (ngx_connection_t *c, ngx_chain_t *in); diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -77,7 +77,7 @@ void ngx_log_error_core(int level, ngx_l /* pid#tid */ len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, - "%d#%d: ", ngx_getpid(), 0); + PID_FMT "#%d: ", ngx_getpid(), 0); #if (HAVE_VARIADIC_MACROS) va_start(args, fmt); diff --git a/src/core/ngx_modules.c b/src/core/ngx_modules.c --- a/src/core/ngx_modules.c +++ b/src/core/ngx_modules.c @@ -17,11 +17,10 @@ extern ngx_module_t ngx_kqueue_module; #if (HAVE_DEVPOLL) extern ngx_module_t ngx_devpoll_module; #endif -#if (HAVE_AIO) -extern ngx_module_t ngx_aio_module; -#endif #if (HAVE_IOCP) extern ngx_module_t ngx_iocp_module; +#elif (HAVE_AIO) +extern ngx_module_t ngx_aio_module; #endif @@ -64,11 +63,10 @@ ngx_module_t *ngx_modules[] = { #if (HAVE_DEVPOLL) &ngx_devpoll_module, #endif -#if (HAVE_AIO) - &ngx_aio_module, -#endif #if (HAVE_IOCP) &ngx_iocp_module, +#elif (HAVE_AIO) + &ngx_aio_module, #endif /* http */ diff --git a/src/event/modules/ngx_iocp_module.c b/src/event/modules/ngx_iocp_module.c --- a/src/event/modules/ngx_iocp_module.c +++ b/src/event/modules/ngx_iocp_module.c @@ -7,16 +7,13 @@ #include #include #include - - -typedef struct { - int threads; -} ngx_iocp_conf_t; +#include static int ngx_iocp_init(ngx_log_t *log); static void ngx_iocp_done(ngx_log_t *log); static int ngx_iocp_add_event(ngx_event_t *ev, int event, u_int key); +static int ngx_iocp_del_connection(ngx_connection_t *c); static int ngx_iocp_process_events(ngx_log_t *log); static void *ngx_iocp_create_conf(ngx_pool_t *pool); static char *ngx_iocp_init_conf(ngx_pool_t *pool, void *conf); @@ -33,6 +30,20 @@ static ngx_command_t ngx_iocp_commands[ offsetof(ngx_iocp_conf_t, threads), NULL}, + {ngx_string("acceptex"), + NGX_EVENT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_iocp_conf_t, acceptex), + NULL}, + + {ngx_string("acceptex_read"), + NGX_EVENT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_iocp_conf_t, acceptex_read), + NULL}, + ngx_null_command }; @@ -48,7 +59,7 @@ ngx_event_module_t ngx_iocp_module_ctx NULL, /* enable an event */ NULL, /* disable an event */ NULL, /* add an connection */ - NULL, /* delete an connection */ + ngx_iocp_del_connection, /* delete an connection */ ngx_iocp_process_events, /* process the events */ ngx_iocp_init, /* init the events */ ngx_iocp_done /* done the events */ @@ -111,10 +122,13 @@ static int ngx_iocp_add_event(ngx_event_ c = (ngx_connection_t *) ev->data; - ngx_log_debug(ev->log, "iocp add: %d, %08x:%08x" _ c->fd _ key _ &ev->ovlp); + c->read->active = 1; + c->write->active = 1; + + ngx_log_debug(ev->log, "iocp add: %d, %d:%08x" _ c->fd _ key _ &ev->ovlp); if (CreateIoCompletionPort((HANDLE) c->fd, iocp, key, 0) == NULL) { - ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CreateIoCompletionPort() failed"); return NGX_ERROR; } @@ -123,6 +137,17 @@ static int ngx_iocp_add_event(ngx_event_ } +static int ngx_iocp_del_connection(ngx_connection_t *c) +{ + if (CancelIo((HANDLE) c->fd) == 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, "CancelIo() failed"); + return NGX_ERROR; + } + + return NGX_OK; +} + + static int ngx_iocp_process_events(ngx_log_t *log) { int rc; @@ -148,7 +173,7 @@ static int ngx_iocp_process_events(ngx_l rc = GetQueuedCompletionStatus(iocp, &bytes, (LPDWORD) &key, (LPOVERLAPPED *) &ovlp, timer); - ngx_log_debug(log, "iocp: %d, %d:%08x:%08x" _ rc _ bytes _ key _ ovlp); + ngx_log_debug(log, "iocp: %d, %d, %d:%08x" _ rc _ bytes _ key _ ovlp); if (rc == 0) { err = ngx_errno; @@ -179,13 +204,17 @@ ngx_log_debug(log, "iocp ev: %08x" _ ev) switch (key) { case NGX_IOCP_IO: ev->ready = 1; - ev->available = bytes; break; case NGX_IOCP_ACCEPT: + if (bytes) { + ev->ready = 1; + } break; } + ev->available = bytes; + ngx_log_debug(log, "iocp ev handler: %08x" _ ev->event_handler); ev->event_handler(ev); @@ -203,6 +232,8 @@ static void *ngx_iocp_create_conf(ngx_po NGX_CONF_ERROR); cf->threads = NGX_CONF_UNSET; + cf->acceptex = NGX_CONF_UNSET; + cf->acceptex_read = NGX_CONF_UNSET; return cf; } @@ -213,6 +244,8 @@ static char *ngx_iocp_init_conf(ngx_pool ngx_iocp_conf_t *cf = conf; ngx_conf_init_value(cf->threads, 0); + ngx_conf_init_value(cf->acceptex, 10); + ngx_conf_init_value(cf->acceptex_read, 1); return NGX_CONF_OK; } diff --git a/src/event/modules/ngx_iocp_module.h b/src/event/modules/ngx_iocp_module.h --- a/src/event/modules/ngx_iocp_module.h +++ b/src/event/modules/ngx_iocp_module.h @@ -2,14 +2,14 @@ #define _NGX_IOCP_MODULE_H_INCLUDED_ -#include -#include -#include +typedef struct { + int threads; + int acceptex; + int acceptex_read; +} ngx_iocp_conf_t; -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); +extern ngx_module_t ngx_iocp_module; #endif /* _NGX_IOCP_MODULE_H_INCLUDED_ */ 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 @@ -378,7 +378,9 @@ static char *ngx_select_init_conf(ngx_po ecf = ngx_event_get_conf(ngx_event_module); - if (ecf->connections > FD_SETSIZE) { + /* the default FD_SETSIZE is 1024U in FreeBSD 5.x */ + + if ((unsigned) ecf->connections > FD_SETSIZE) { return "maximum number of connections " "supported by select() is " ngx_value(FD_SETSIZE); } 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 @@ -1,8 +1,6 @@ #include #include -#include -#include #include @@ -23,11 +21,6 @@ extern ngx_module_t ngx_devpoll_module; #include #endif -#if (HAVE_IOCP) -#include -#include -#endif - static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_event_use(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -123,11 +116,14 @@ ngx_module_t ngx_event_module = { int ngx_pre_thread(ngx_array_t *ls, ngx_pool_t *pool, ngx_log_t *log) { int m, i, fd; - ngx_listen_t *s; - ngx_event_t *ev; + ngx_event_t *rev, *wev; + ngx_listening_t *s; ngx_connection_t *c; ngx_event_conf_t *ecf; ngx_event_module_t *module; +#if (WIN32) + ngx_iocp_conf_t *iocpcf; +#endif ecf = ngx_event_get_conf(ngx_event_module); @@ -161,71 +157,76 @@ ngx_log_debug(log, "TYPE: %d" _ ecf->use NGX_ERROR); /* for each listening socket */ - s = (ngx_listen_t *) ls->elts; - for (i = 0; i < ls->nelts; i++) { + + for (s = ls->elts, i = 0; i < ls->nelts; i++) { fd = s[i].fd; +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + c = &ngx_connections[fd / 4]; + rev = &ngx_read_events[fd / 4]; + wev = &ngx_write_events[fd / 4]; +#else c = &ngx_connections[fd]; - ev = &ngx_read_events[fd]; + rev = &ngx_read_events[fd]; + wev = &ngx_write_events[fd]; +#endif ngx_memzero(c, sizeof(ngx_connection_t)); - ngx_memzero(ev, sizeof(ngx_event_t)); + ngx_memzero(rev, sizeof(ngx_event_t)); c->fd = fd; - c->family = s[i].family; - c->socklen = s[i].socklen; - c->sockaddr = ngx_palloc(pool, s[i].socklen); - c->addr = s[i].addr; - c->addr_text = s[i].addr_text; - c->addr_text_max_len = s[i].addr_text_max_len; - c->post_accept_timeout = s[i].post_accept_timeout; + c->listening = &s[i]; - c->handler = s[i].handler; c->ctx = s[i].ctx; c->servers = s[i].servers; c->log = s[i].log; - c->pool_size = s[i].pool_size; - ngx_test_null(ev->log, - ngx_palloc(pool, sizeof(ngx_log_t)), - NGX_ERROR); + ngx_test_null(rev->log, ngx_palloc(pool, sizeof(ngx_log_t)), NGX_ERROR); - ngx_memcpy(ev->log, c->log, sizeof(ngx_log_t)); - c->read = ev; - ev->data = c; - ev->index = NGX_INVALID_INDEX; + ngx_memcpy(rev->log, c->log, sizeof(ngx_log_t)); + c->read = rev; + c->write = wev; + rev->data = c; + rev->index = NGX_INVALID_INDEX; #if 0 - ev->listening = 1; + rev->listening = 1; #endif - ev->available = 0; + rev->available = 0; #if (HAVE_DEFERRED_ACCEPT) - ev->deferred_accept = s[i].deferred_accept; + rev->deferred_accept = s[i].deferred_accept; #endif -#if (HAVE_IOCP) +#if (WIN32) if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { - ev->event_handler = &ngx_event_acceptex; + rev->event_handler = &ngx_event_acceptex; - /* LOOK: we call ngx_iocp_add_event() also - in ngx_event_post_acceptex() */ - if (ngx_iocp_add_event(ev) == NGX_ERROR) { + if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } - ngx_event_post_acceptex(&s[i], 1); + iocpcf = ngx_event_get_conf(ngx_iocp_module); + if (ngx_event_post_acceptex(&s[i], iocpcf->acceptex) == NGX_ERROR) { + return NGX_ERROR; + } } else { - ev->event_handler = &ngx_event_accept; + rev->event_handler = &ngx_event_accept; + ngx_add_event(rev, NGX_READ_EVENT, 0); } #else - ev->event_handler = &ngx_event_accept; - ngx_add_event(ev, NGX_READ_EVENT, 0); + rev->event_handler = &ngx_event_accept; + ngx_add_event(rev, NGX_READ_EVENT, 0); #endif } @@ -384,14 +385,6 @@ static char *ngx_event_init_conf(ngx_poo #endif -#if (WIN32) - /* - * Winsock assignes a socket number according to 4 * N + M, - * where M is the constant 32 (98SE), 88 (NT) or 100 (W2K). - * So to find a connection we divide a socket number by 4. - */ -#endif - ngx_conf_init_value(ecf->timer_queues, 10); return NGX_CONF_OK; 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 @@ -270,11 +270,6 @@ typedef struct { #define ngx_del_conn ngx_event_actions.del_conn #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) @@ -283,17 +278,33 @@ typedef struct { #define ngx_event_recv ngx_io.recv #define ngx_write_chain ngx_io.send_chain #endif +#endif #endif + + + +/* ***************************** */ + +#define ngx_recv ngx_io.recv +#define ngx_write_chain ngx_io.send_chain + + +#define ngx_add_timer ngx_event_add_timer +#define ngx_del_timer ngx_event_del_timer + + #if (HAVE_IOCP_EVENT) #define NGX_IOCP_ACCEPT 0 #define NGX_IOCP_IO 1 #endif +/* ***************************** */ -#define ngx_del_timer ngx_event_del_timer + + @@ -309,6 +320,8 @@ extern int ngx_event_f +/* ***************************** */ + #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ #define NGX_EVENT_CONF 0x00200000 @@ -342,6 +355,16 @@ extern ngx_module_t ngx_event_mod void ngx_event_accept(ngx_event_t *ev); +#if (WIN32) +void ngx_event_acceptex(ngx_event_t *ev); +int ngx_event_post_acceptex(ngx_listening_t *ls, int n); +#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); @@ -351,7 +374,15 @@ int ngx_pre_thread(ngx_array_t *ls, ngx void ngx_worker(ngx_log_t *log); +/* ***************************** */ + + #include +#if (WIN32) +#include +#endif + +/* ***************************** */ #endif /* _NGX_EVENT_H_INCLUDED_ */ 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 @@ -30,21 +30,23 @@ void ngx_event_accept(ngx_event_t *ev) /* * Create the pool before accept() to avoid copy the sockaddr. - * Although accept() can fail it's uncommon case + * Although accept() can fail it's an uncommon case * and the pool can be got from the free pool list */ - pool = ngx_create_pool(ls->pool_size, ev->log); + pool = ngx_create_pool(ls->listening->pool_size, ev->log); if (pool == NULL) { return; } - sa = ngx_palloc(pool, ls->socklen); + sa = ngx_palloc(pool, ls->listening->socklen); if (sa == NULL) { return; } - len = ls->socklen; + len = ls->listening->socklen; + +ngx_log_debug(ev->log, "ADDR %s" _ ls->listening->addr_text.data); s = accept(ls->fd, sa, &len); if (s == -1) { @@ -52,12 +54,13 @@ void ngx_event_accept(ngx_event_t *ev) if (err == NGX_EAGAIN) { ngx_log_error(NGX_LOG_NOTICE, ev->log, err, - "EAGAIN while accept() %s", ls->addr_text.data); + "EAGAIN while accept() %s", + ls->listening->addr_text.data); return; } ngx_log_error(NGX_LOG_ALERT, ev->log, err, - "accept() %s failed", ls->addr_text.data); + "accept() %s failed", ls->listening->addr_text.data); ngx_destroy_pool(pool); return; @@ -70,12 +73,12 @@ void ngx_event_accept(ngx_event_t *ev) "accept() %s returned socket #%d while " "only %d connections was configured, " "sleeping for 1 second", - ls->addr_text.data, s, ecf->connections); + ls->listening->addr_text.data, s, ecf->connections); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_close_socket_n " %s failed", - ls->addr_text.data); + ls->listening->addr_text.data); } ngx_msleep(1000); @@ -91,12 +94,12 @@ void ngx_event_accept(ngx_event_t *ev) 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); + ls->listening->addr_text.data); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_close_socket_n " %s failed", - ls->addr_text.data); + ls->listening->addr_text.data); } ngx_destroy_pool(pool); @@ -109,12 +112,12 @@ void ngx_event_accept(ngx_event_t *ev) 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); + ls->listening->addr_text.data); if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_close_socket_n " %s failed", - ls->addr_text.data); + ls->listening->addr_text.data); } ngx_destroy_pool(pool); @@ -123,9 +126,26 @@ void ngx_event_accept(ngx_event_t *ev) } } +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + exit(1); + } + + rev = &ngx_read_events[s / 4]; + wev = &ngx_write_events[s / 4]; + c = &ngx_connections[s / 4]; +#else rev = &ngx_read_events[s]; wev = &ngx_write_events[s]; c = &ngx_connections[s]; +#endif instance = rev->instance; @@ -135,12 +155,9 @@ void ngx_event_accept(ngx_event_t *ev) c->pool = pool; + c->listening = ls->listening; c->sockaddr = sa; - c->family = ls->family; c->socklen = len; - c->addr = ls->addr; - c->addr_text_max_len = ls->addr_text_max_len; - c->post_accept_timeout = ls->post_accept_timeout; rev->instance = wev->instance = !instance; @@ -182,7 +199,7 @@ void ngx_event_accept(ngx_event_t *ev) if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_close_socket_n " %s failed", - ls->addr_text.data); + ls->listening->addr_text.data); } ngx_destroy_pool(pool); @@ -190,7 +207,7 @@ void ngx_event_accept(ngx_event_t *ev) } } - ls->handler(c); + ls->listening->handler(c); if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { ev->available--; diff --git a/src/event/ngx_event_acceptex.c b/src/event/ngx_event_acceptex.c --- a/src/event/ngx_event_acceptex.c +++ b/src/event/ngx_event_acceptex.c @@ -1,14 +1,8 @@ #include #include - -#include - #include -#if 0 -#include -#include -#endif +#include void ngx_event_acceptex(ngx_event_t *rev) @@ -17,11 +11,9 @@ void ngx_event_acceptex(ngx_event_t *rev c = (ngx_connection_t *) rev->data; -ngx_log_debug(rev->log, "ADDR: %s" _ c->addr_text.data); - if (rev->ovlp.error) { - ngx_log_error(NGX_LOG_CRIT, rev->log, rev->ovlp.error, - "AcceptEx() failed for %s", c->addr_text.data); + ngx_log_error(NGX_LOG_CRIT, c->log, rev->ovlp.error, + "AcceptEx() %s failed", c->listening->addr_text.data); return; } @@ -30,36 +22,45 @@ ngx_log_debug(rev->log, "ADDR: %s" _ c-> if (setsockopt(c->fd, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, (char *)&c->listening->fd, sizeof(ngx_socket_t)) == -1) { - ngx_log_error(NGX_LOG_CRIT, ev->log, ngx_socket_errno, + ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, "setsockopt(SO_UPDATE_ACCEPT_CONTEXT) failed for %s", c->addr_text.data); } else { - accept_context_updated = 1; + c->accept_context_updated = 1; } - getacceptexsockaddrs(c->data, 0, - c->socklen + 16, c->socklen + 16, + getacceptexsockaddrs(c->buffer->pos, c->listening->post_accept_buffer_size, + c->listening->socklen + 16, + c->listening->socklen + 16, &c->local_sockaddr, &c->local_socklen, &c->sockaddr, &c->socklen); + if (c->listening->post_accept_buffer_size) { + c->buffer->last += rev->available; + c->buffer->end = c->buffer->start + + c->listening->post_accept_buffer_size; + + } else { + c->buffer = NULL; + } + ngx_event_post_acceptex(c->listening, 1); - /* STUB: InterlockedInc() */ + /* TODO: MT */ c->number = ngx_connection_counter++; - c->handler(c); + c->listening->handler(c); return; } -int ngx_event_post_acceptex(ngx_listen_t *ls, int n) +int ngx_event_post_acceptex(ngx_listening_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; @@ -68,29 +69,36 @@ int ngx_event_post_acceptex(ngx_listen_t /* 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); + ngx_log_debug(ls->log, ngx_socket_n ": %d:%d" _ s _ ls->flags); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, ls->log, ngx_socket_errno, - ngx_socket_n " for AcceptEx() post failed"); + ngx_socket_n " for AcceptEx() %s post failed", + ls->addr_text.data); return NGX_ERROR; } - ngx_test_null(pool, ngx_create_pool(ls->pool_size, ls->log), NGX_ERROR); + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ - rev = &ngx_read_events[s]; - wev = &ngx_write_events[s]; - c = &ngx_connections[s]; + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + exit(1); + } + + rev = &ngx_read_events[s / 4]; + wev = &ngx_write_events[s / 4]; + c = &ngx_connections[s / 4]; 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; @@ -100,53 +108,55 @@ int ngx_event_post_acceptex(ngx_listen_t 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; - c->ctx = ls->ctx; c->servers = ls->servers; - ngx_test_null(c->data, ngx_palloc(pool, 2 * (c->socklen + 16)), + c->unexpected_eof = 1; + wev->write = 1; + rev->event_handler = ngx_event_acceptex; + + ngx_test_null(c->pool, + ngx_create_pool(ls->pool_size, ls->log), NGX_ERROR); - ngx_test_null(c->local_sockaddr, ngx_palloc(pool, c->socklen), + + ngx_test_null(c->buffer, + ngx_create_temp_hunk(c->pool, + ls->post_accept_buffer_size + + 2 * (c->listening->socklen + 16), + 0, 0), NGX_ERROR); - ngx_test_null(c->sockaddr, ngx_palloc(pool, c->socklen), + + ngx_test_null(c->local_sockaddr, ngx_palloc(c->pool, ls->socklen), + NGX_ERROR); + + ngx_test_null(c->sockaddr, ngx_palloc(c->pool, ls->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; + c->read->log = c->write->log = c->log; if (ngx_add_event(rev, 0, NGX_IOCP_IO) == NGX_ERROR) { return NGX_ERROR; } - if (acceptex(ls->fd, s, c->data, 0, - c->socklen + 16, c->socklen + 16, - &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0) { + if (acceptex(ls->fd, s, c->buffer->pos, ls->post_accept_buffer_size, + ls->socklen + 16, ls->socklen + 16, + &rcvd, (LPOVERLAPPED) &rev->ovlp) == 0) + { err = ngx_socket_errno; - if (err == WSA_IO_PENDING) { - return NGX_OK; - } + if (err != WSA_IO_PENDING) { + ngx_log_error(NGX_LOG_ALERT, ls->log, err, + "AcceptEx() %s falied", ls->addr_text.data); - ngx_log_error(NGX_LOG_ALERT, ls->log, err, - "AcceptEx(%s) falied", ls->addr_text.data); - - return NGX_ERROR; + return NGX_ERROR; + } } } diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -1,14 +1,8 @@ #include - #include -#include -#include -#include #include -#include - static ngx_event_t *ngx_timer_queue; static int ngx_timer_cur_queue; @@ -49,7 +43,7 @@ void ngx_event_add_timer(ngx_event_t *ev ngx_event_t *e; #if (NGX_DEBUG_EVENT) - ngx_connection_t *c = (ngx_connection_t *) ev->data; + ngx_connection_t *c = ev->data; ngx_log_debug(ev->log, "set timer: %d:%d, slot: %d" _ c->fd _ timer _ ngx_timer_cur_queue); #endif 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 @@ -3,9 +3,7 @@ #include - -#include -#include +#include #include @@ -20,8 +18,8 @@ void ngx_event_expire_timers(ngx_msec_t ngx_inline static void ngx_event_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)); + ngx_connection_t *c = ev->data; + ngx_log_debug(ev->log, "del timer: %d" _ c->fd); #endif if (!ev->timer_next || !ev->timer_prev) { diff --git a/src/http/modules/ngx_http_chunked_filter.c b/src/http/modules/ngx_http_chunked_filter.c --- a/src/http/modules/ngx_http_chunked_filter.c +++ b/src/http/modules/ngx_http_chunked_filter.c @@ -85,7 +85,7 @@ static int ngx_http_chunked_body_filter( } ngx_test_null(chunk, ngx_palloc(r->pool, 11), NGX_ERROR); - len = ngx_snprintf(chunk, 11, "%x" CRLF, size); + len = ngx_snprintf(chunk, 11, SIZEX_FMT CRLF, size); ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP; 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 @@ -240,7 +240,7 @@ static char *ngx_http_index_merge_conf(n if (conf->max_index_len == 0) { if (prev->max_index_len != 0) { - ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t)); + ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t)); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_range_filter.c b/src/http/modules/ngx_http_range_filter.c --- a/src/http/modules/ngx_http_range_filter.c +++ b/src/http/modules/ngx_http_range_filter.c @@ -61,6 +61,10 @@ static int ngx_http_range_header_filter( ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t), NGX_ERROR); +#if (NGX_SUPPRESS_WARN) + range = NULL; +#endif + rc = 0; p = r->headers_in.range->value.data + 6; @@ -149,7 +153,7 @@ static int ngx_http_range_header_filter( ngx_palloc(r->pool, 8 + 20 + 1), NGX_ERROR); - r->headers_out.content_range->value.len = + r->headers_out.content_range->value.len = ngx_snprintf(r->headers_out.content_range->value.data, 8 + 20 + 1, "bytes */" OFF_FMT, r->headers_out.content_length); @@ -170,7 +174,7 @@ static int ngx_http_range_header_filter( ngx_palloc(r->pool, 6 + 20 + 1 + 20 + 1 + 20 + 1), NGX_ERROR); - r->headers_out.content_range->value.len = + r->headers_out.content_range->value.len = ngx_snprintf(r->headers_out.content_range->value.data, 6 + 20 + 1 + 20 + 1 + 20 + 1, "bytes " OFF_FMT "-" OFF_FMT "/" OFF_FMT, @@ -244,7 +248,7 @@ static int ngx_http_range_header_filter( ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5), NGX_ERROR); - range[i].content_range.len = + range[i].content_range.len = ngx_snprintf(range[i].content_range.data, 20 + 1 + 20 + 1 + 20 + 5, OFF_FMT "-" OFF_FMT "/" OFF_FMT CRLF CRLF, 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 @@ -1,13 +1,10 @@ #include #include - -#include - +#include #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, void *conf); @@ -54,17 +51,20 @@ static char *ngx_http_block(ngx_conf_t * char *rv; struct sockaddr_in *addr_in; ngx_array_t in_ports; - ngx_listen_t *ls; + ngx_listening_t *ls; ngx_http_module_t *module; ngx_conf_t pcf; ngx_http_conf_ctx_t *ctx; ngx_http_in_port_t *in_port, *inport; ngx_http_in_addr_t *in_addr, *inaddr; ngx_http_core_main_conf_t *cmcf; - ngx_http_core_srv_conf_t **cscfp; + ngx_http_core_srv_conf_t **cscfp, *cscf; ngx_http_core_loc_conf_t **clcfp; ngx_http_listen_t *lscf; ngx_http_server_name_t *s_name, *name; +#if (WIN32) + ngx_iocp_conf_t *iocpcf; +#endif /* the main http context */ ngx_test_null(ctx, @@ -431,7 +431,7 @@ static char *ngx_http_block(ngx_conf_t * ngx_test_null(ls, ngx_push_array(&ngx_listening_sockets), NGX_CONF_ERROR); - ngx_memzero(ls, sizeof(ngx_listen_t)); + ngx_memzero(ls, sizeof(ngx_listening_t)); ngx_test_null(addr_in, ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)), @@ -456,7 +456,7 @@ static char *ngx_http_block(ngx_conf_t * ls->family = AF_INET; ls->type = SOCK_STREAM; ls->protocol = IPPROTO_IP; -#if (NGX_OVERLAPPED) +#if (WIN32) ls->flags = WSA_FLAG_OVERLAPPED; #endif ls->sockaddr = (struct sockaddr *) addr_in; @@ -468,8 +468,18 @@ static char *ngx_http_block(ngx_conf_t * ls->handler = ngx_http_init_connection; ls->log = cf->log; - ls->pool_size = cmcf->connection_pool_size; - ls->post_accept_timeout = cmcf->post_accept_timeout; + + cscf = in_addr[a].core_srv_conf; + ls->pool_size = cscf->connection_pool_size; + ls->post_accept_timeout = cscf->post_accept_timeout; + +#if (WIN32) + iocpcf = ngx_event_get_conf(ngx_iocp_module); + if (iocpcf->acceptex_read) { + ls->post_accept_buffer_size = cscf->client_header_buffer_size; + } +#endif + ls->ctx = ctx; if (in_port[p].addrs.nelts > 1) { 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 @@ -1,10 +1,6 @@ #include #include - -/* ???? */ -#include - #include #include @@ -46,17 +42,17 @@ static ngx_command_t ngx_http_core_comm NULL}, {ngx_string("connection_pool_size"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_core_main_conf_t, connection_pool_size), + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_core_srv_conf_t, connection_pool_size), NULL}, {ngx_string("post_accept_timeout"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, - NGX_HTTP_MAIN_CONF_OFFSET, - offsetof(ngx_http_core_main_conf_t, post_accept_timeout), + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_core_srv_conf_t, post_accept_timeout), NULL}, {ngx_string("request_pool_size"), @@ -738,9 +734,6 @@ static void *ngx_http_core_create_main_c ngx_palloc(pool, sizeof(ngx_http_core_main_conf_t)), NGX_CONF_ERROR); - cmcf->connection_pool_size = NGX_CONF_UNSET; - cmcf->post_accept_timeout = NGX_CONF_UNSET; - ngx_init_array(cmcf->servers, pool, 5, sizeof(ngx_http_core_srv_conf_t *), NGX_CONF_ERROR); @@ -752,8 +745,7 @@ static char *ngx_http_core_init_main_con { ngx_http_core_main_conf_t *cmcf = conf; - ngx_conf_init_size_value(cmcf->connection_pool_size, 16384); - ngx_conf_init_msec_value(cmcf->post_accept_timeout, 30000); + /* TODO: remove it if no directives */ return NGX_CONF_OK; } @@ -773,6 +765,8 @@ static void *ngx_http_core_create_srv_co ngx_init_array(cscf->server_names, pool, 5, sizeof(ngx_http_server_name_t), NGX_CONF_ERROR); + cscf->connection_pool_size = NGX_CONF_UNSET; + cscf->post_accept_timeout = NGX_CONF_UNSET; cscf->request_pool_size = NGX_CONF_UNSET; cscf->client_header_timeout = NGX_CONF_UNSET; cscf->client_header_buffer_size = NGX_CONF_UNSET; @@ -827,6 +821,10 @@ static char *ngx_http_core_merge_srv_con n->core_srv_conf = conf; } + ngx_conf_merge_size_value(conf->connection_pool_size, + prev->connection_pool_size, 16384); + ngx_conf_merge_msec_value(conf->post_accept_timeout, + prev->post_accept_timeout, 30000); ngx_conf_merge_size_value(conf->request_pool_size, prev->request_pool_size, 16384); ngx_conf_merge_msec_value(conf->client_header_timeout, @@ -945,7 +943,7 @@ static char *ngx_set_listen(ngx_conf_t * ngx_str_t *args; ngx_http_listen_t *ls; - /* TODO: check duplicate 'listen' directives, + /* TODO: check duplicate 'listen' directives, add resolved name to server names ??? */ ngx_test_null(ls, ngx_push_array(&scf->listen), NGX_CONF_ERROR); 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 @@ -18,9 +18,6 @@ typedef struct { typedef struct { - int connection_pool_size; - int post_accept_timeout; - ngx_array_t servers; /* array of ngx_http_core_srv_conf_t */ } ngx_http_core_main_conf_t; @@ -36,6 +33,8 @@ typedef struct { ngx_http_conf_ctx_t *ctx; /* server ctx */ + ngx_msec_t post_accept_timeout; + ssize_t connection_pool_size; size_t request_pool_size; ngx_msec_t client_header_timeout; size_t client_header_buffer_size; 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 @@ -67,14 +67,15 @@ void ngx_http_init_connection(ngx_connec ngx_event_t *rev; ngx_http_log_ctx_t *lcx; - c->addr_text.data = ngx_palloc(c->pool, c->addr_text_max_len); + c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_http_close_connection(c); return; } - c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr, - c->addr_text.data, c->addr_text_max_len); + c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, + c->addr_text.data, + c->listening->addr_text_max_len); if (c->addr_text.len == 0) { ngx_http_close_connection(c); return; @@ -100,7 +101,7 @@ void ngx_http_init_connection(ngx_connec return; } - ngx_add_timer(rev, c->post_accept_timeout); + ngx_add_timer(rev, c->listening->post_accept_timeout); rev->timer_set = 1; if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) { @@ -158,19 +159,30 @@ static void ngx_http_init_request(ngx_ev if (in_port->addrs.nelts > 1) { - /* there're the several addresses on this port and one of them - is "*:port" so getsockname() is needed to determine - the server address */ + /* + * there're the several addresses on this port and one of them + * is "*:port" so getsockname() is needed to determine + * the server address. + * AcceptEx() already gave this address. + */ - /* TODO: AcceptEx() already gave this sockaddr_in */ +#if (WIN32) + if (c->local_sockaddr) { + r->in_addr = + ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; - len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) { - ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno, - "getsockname() failed"); - ngx_http_close_connection(c); - return; + } else { +#endif + len = sizeof(struct sockaddr_in); + if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) { + ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno, + "getsockname() failed"); + ngx_http_close_connection(c); + return; + } +#if (WIN32) } +#endif r->in_addr = addr_in.sin_addr.s_addr; @@ -689,18 +701,19 @@ static ssize_t ngx_http_read_request_hea ngx_event_t *rev; ngx_http_core_srv_conf_t *cscf; + rev = r->connection->read; + n = r->header_in->last - r->header_in->pos; if (n > 0) { + rev->ready = 0; return n; } - n = ngx_event_recv(r->connection, r->header_in->last, - r->header_in->end - r->header_in->last); + n = ngx_recv(r->connection, r->header_in->last, + r->header_in->end - r->header_in->last); if (n == NGX_AGAIN) { - rev = r->connection->read; - if (!r->header_timeout_set) { if (rev->timer_set) { ngx_del_timer(rev); @@ -773,6 +786,20 @@ void ngx_http_finalize_request(ngx_http_ } rc = ngx_http_special_response_handler(r, rc); + + if (rc == NGX_AGAIN) { + return; + } + + if (rc == NGX_ERROR) { + ngx_http_close_request(r, 0); + ngx_http_close_connection(r->connection); + return; + } + + } else if (rc == NGX_ERROR) { + r->keepalive = 0; + r->lingering_close = 0; } rev = r->connection->read; @@ -1028,7 +1055,7 @@ static int ngx_http_read_discarded_body( size = clcf->discarded_buffer_size; } - n = ngx_event_recv(r->connection, r->discarded_buffer, size); + n = ngx_recv(r->connection, r->discarded_buffer, size); if (n == NGX_ERROR) { return NGX_HTTP_BAD_REQUEST; } @@ -1169,7 +1196,7 @@ static void ngx_http_keepalive_handler(n rev->ignore_econnreset = 1; ngx_set_socket_errno(0); - n = ngx_event_recv(c, c->buffer->last, c->buffer->end - c->buffer->last); + n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last); rev->ignore_econnreset = 0; if (n == NGX_AGAIN) { @@ -1307,7 +1334,7 @@ static void ngx_http_lingering_close_han } do { - n = ngx_event_recv(c, r->discarded_buffer, clcf->discarded_buffer_size); + n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size); ngx_log_debug(c->log, "lingering read: %d" _ n); 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 @@ -5,7 +5,7 @@ typedef struct { - size_t hunk_size; + ssize_t hunk_size; } ngx_http_output_filter_conf_t; 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 @@ -12,6 +12,16 @@ static char error_tail[] = ; +static char msie_stub[] = +"" CRLF +"" CRLF +"" CRLF +"" CRLF +"" CRLF +"" CRLF +; + + static char error_302_page[] = "" CRLF "302 Found" CRLF @@ -134,8 +144,8 @@ static ngx_str_t error_pages[] = { int ngx_http_special_response_handler(ngx_http_request_t *r, int error) { - int err; - ngx_hunk_t *message, *tail; + int err, rc; + ngx_hunk_t *h; r->headers_out.status = error; @@ -172,7 +182,8 @@ int ngx_http_special_response_handler(ng if (error_pages[err].len) { r->headers_out.content_length = error_pages[err].len - + sizeof(error_tail); + + sizeof(error_tail) - 1 + + sizeof(msie_stub) - 1; ngx_test_null(r->headers_out.content_type, ngx_push_table(r->headers_out.headers), @@ -187,29 +198,63 @@ int ngx_http_special_response_handler(ng r->headers_out.content_length = -1; } - if (ngx_http_send_header(r) == NGX_ERROR) { + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR) { return NGX_ERROR; } + if (r->header_only) { + if (rc == NGX_AGAIN) { + ngx_http_set_write_handler(r); + return NGX_AGAIN; + } + + return NGX_OK; + } + if (error_pages[err].len == 0) { return NGX_OK; } - ngx_test_null(message, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); - message->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; - message->pos = error_pages[err].data; - message->last = error_pages[err].data + error_pages[err].len; + h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; + h->pos = error_pages[err].data; + h->last = error_pages[err].data + error_pages[err].len; - if (ngx_http_output_filter(r, message) == NGX_ERROR) { + if (ngx_http_output_filter(r, h) == NGX_ERROR) { return NGX_ERROR; } - ngx_test_null(tail, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); + + h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; + h->pos = error_tail; + h->last = error_tail + sizeof(error_tail) - 1; + + if (1) { + if (ngx_http_output_filter(r, h) == NGX_ERROR) { + return NGX_ERROR; + } + + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); - tail->type = NGX_HUNK_MEMORY|NGX_HUNK_LAST|NGX_HUNK_IN_MEMORY; - tail->pos = error_tail; - tail->last = error_tail + sizeof(error_tail); + h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; + h->pos = msie_stub; + h->last = msie_stub + sizeof(msie_stub) - 1; + } + + h->type |= NGX_HUNK_LAST; + + rc = ngx_http_output_filter(r, h); - return ngx_http_output_filter(r, tail); + if (r->main == NULL) { + if (rc == NGX_AGAIN) { + ngx_http_set_write_handler(r); + return NGX_AGAIN; + } + } + + return NGX_OK; + } 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 @@ -1,11 +1,12 @@ #include #include +#include #include typedef struct { - size_t buffer_output; + ssize_t buffer_output; } ngx_http_write_filter_conf_t; @@ -139,11 +140,7 @@ int ngx_http_write_filter(ngx_http_reque return NGX_AGAIN; } -#if 1 chain = ngx_write_chain(r->connection, ctx->out); -#else - chain = ngx_write_chain(r->connection, ctx->out, flush); -#endif #if (NGX_DEBUG_WRITE_FILTER) ngx_log_debug(r->connection->log, "write filter %x" _ chain); diff --git a/src/os/unix/ngx_aio_read.c b/src/os/unix/ngx_aio_read.c --- a/src/os/unix/ngx_aio_read.c +++ b/src/os/unix/ngx_aio_read.c @@ -1,6 +1,7 @@ #include #include +#include #include #if (HAVE_KQUEUE) diff --git a/src/os/unix/ngx_aio_write.c b/src/os/unix/ngx_aio_write.c --- a/src/os/unix/ngx_aio_write.c +++ b/src/os/unix/ngx_aio_write.c @@ -1,6 +1,7 @@ #include #include +#include #include #if (HAVE_KQUEUE) @@ -29,6 +30,7 @@ ssize_t ngx_aio_write(ngx_connection_t * ngx_log_debug(ev->log, "aio: ev->ready: %d" _ ev->ready); ngx_log_debug(ev->log, "aio: aiocb: %08x" _ &ev->aiocb); +#if 0 if (ev->timedout) { ngx_set_socket_errno(NGX_ETIMEDOUT); ngx_log_error(NGX_LOG_ERR, ev->log, 0, "aio_write() timed out"); @@ -46,6 +48,7 @@ ngx_log_debug(ev->log, "aio: aiocb: %08x ev->ready = 1; } +#endif first = 0; diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -22,9 +22,22 @@ #include -#define QD_FMT "%qd" -#define QX_FMT "%qx" -#define OFF_FMT "%qd" +/* STUB */ +#define QD_FMT "%lld" +#define QX_FMT "%llx" +/**/ + +#if (i386) +#define OFF_FMT "%lld" +#define SIZE_FMT "%d" +#define SIZEX_FMT "%x" +#else +#define OFF_FMT "%ld" +#define SIZE_FMT "%ld" +#define SIZEX_FMT "%lx" +#endif + +#define PID_FMT "%d" #ifndef HAVE_SELECT diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -15,7 +15,8 @@ Until FreeBSD 4.5 the turning TCP_NOPUSH off does not not flush the pending data that less than MSS and the data sent with 5 second delay. - So we use TCP_NOPUSH on FreeBSD 4.5+ only. + So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection + is not needed not keepalive. */ @@ -23,7 +24,7 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( { int rc, eintr, tcp_nopush; char *prev; - size_t hsize, size; + ssize_t hsize, size; off_t sent; struct iovec *iov; struct sf_hdtr hdtr; diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -29,14 +29,11 @@ #include -typedef unsigned int u_int; -typedef unsigned short u_short; -typedef unsigned char u_char; - -#define QD_FMT "%qd" -#define QX_FMT "%qx" -#define OFF_FMT "%qd" +#define QD_FMT "%qd" +#define QX_FMT "%qx" +#define OFF_FMT "%qd" +#define PID_FMT "%d" #ifndef HAVE_SELECT @@ -63,7 +60,7 @@ typedef unsigned char u_char; #ifndef HAVE_FIONBIO -#define HAVE_FIONBIO 1 +#define HAVE_FIONBIO 1 #endif diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -1,6 +1,7 @@ #include #include +#include ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *entry) diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -1,6 +1,7 @@ #include #include +#include static int ngx_unix_recv_error(ngx_event_t *rev, ngx_err_t err); diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c --- a/src/os/unix/ngx_socket.c +++ b/src/os/unix/ngx_socket.c @@ -55,8 +55,7 @@ int ngx_tcp_push(ngx_socket_t s) (const void *) &tcp_nopush, sizeof(int)); } -#else - +#else int ngx_tcp_nopush(ngx_socket_t s) { diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -30,6 +30,7 @@ typedef uint32_t u_int32_t; #define QD_FMT "%lld" #define QX_FMT "%llx" #define OFF_FMT "%lld" +#define PID_FMT "%ld" #ifndef HAVE_SELECT @@ -62,7 +63,7 @@ typedef uint32_t u_int32_t; #ifndef HAVE_FIONBIO -#define HAVE_FIONBIO 1 +#define HAVE_FIONBIO 1 #endif diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -6,15 +6,14 @@ ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in) { char *prev; - size_t size; - ssize_t n; + ssize_t n, size; off_t sent; struct iovec *iov; ngx_err_t err; - ngx_array_t io; + ngx_array_t iovecs; ngx_chain_t *ce; - ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); + ngx_init_array(iovecs, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); prev = NULL; iov = NULL; @@ -27,14 +26,14 @@ ngx_chain_t *ngx_writev_chain(ngx_connec prev = ce->hunk->last; } else { - ngx_test_null(iov, ngx_push_array(&io), NGX_CHAIN_ERROR); + ngx_test_null(iov, ngx_push_array(&iovecs), NGX_CHAIN_ERROR); iov->iov_base = ce->hunk->pos; iov->iov_len = ce->hunk->last - ce->hunk->pos; prev = ce->hunk->last; } } - n = writev(c->fd, (struct iovec *) io.elts, io.nelts); + n = writev(c->fd, iovecs.elts, iovecs.nelts); if (n == -1) { err = ngx_errno; @@ -93,7 +92,7 @@ ngx_log_debug(c->log, "SIZE: %d" _ size) break; } - ngx_destroy_array(&io); + ngx_destroy_array(&iovecs); return ce; } diff --git a/src/os/win32/ngx_errno.c b/src/os/win32/ngx_errno.c --- a/src/os/win32/ngx_errno.c +++ b/src/os/win32/ngx_errno.c @@ -9,9 +9,29 @@ #include +ngx_str_t wsa_errors[] = { + ngx_string("Invalid argument"), /* 10022 */ + ngx_null_string, /* 10023 */ + ngx_null_string, /* 10024 */ + ngx_null_string, /* 10025 */ + ngx_null_string, /* 10026 */ + ngx_null_string, /* 10027 */ + ngx_null_string, /* 10028 */ + ngx_null_string, /* 10029 */ + ngx_null_string, /* 10030 */ + ngx_null_string, /* 10031 */ + ngx_null_string, /* 10032 */ + ngx_null_string, /* 10033 */ + ngx_null_string, /* 10034 */ + ngx_string("Resource temporarily unavailable") /* 10035 */ +}; + + int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size) { - int len; + int n; + u_int len; + ngx_err_t format_error; len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, @@ -19,12 +39,28 @@ int ngx_strerror_r(ngx_err_t err, char * MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errstr, size, NULL); - /* add WSA error messages */ + if (len == 0) { + format_error = GetLastError(); + + if (format_error == ERROR_MR_MID_NOT_FOUND) { + n = err - WSABASEERR - 22; + + if (n >= 0 && n < 14) { + len = wsa_errors[n].len; - if (len == 0) { + if (len) { + if (len > size) { + len = size; + } + + ngx_memcpy(errstr, wsa_errors[n].data, len); + return len; + } + } + } len = ngx_snprintf(errstr, size, - "FormatMessage error:(%d)", GetLastError()); + "FormatMessage() error:(%d)", format_error); return len; } diff --git a/src/os/win32/ngx_os_init.h b/src/os/win32/ngx_os_init.h --- a/src/os/win32/ngx_os_init.h +++ b/src/os/win32/ngx_os_init.h @@ -8,5 +8,7 @@ int ngx_os_init(ngx_log_t *log); +ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size); + #endif /* _NGX_OS_INIT_H_INCLUDED_ */ 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 @@ -16,6 +16,7 @@ typedef int socklen_t; #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); @@ -36,4 +37,11 @@ extern LPFN_GETACCEPTEXSOCKADDRS getacc extern LPFN_TRANSMITFILE transmitfile; +ngx_inline int ngx_tcp_push(s) { + return 0; +} + +#define ngx_tcp_push_n "tcp_push()" + + #endif /* _NGX_SOCKET_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_types.h b/src/os/win32/ngx_types.h --- a/src/os/win32/ngx_types.h +++ b/src/os/win32/ngx_types.h @@ -19,6 +19,7 @@ typedef BY_HANDLE_FILE_INFORMATION ngx_ #define QD_FMT "%I64d" #define QX_FMT "%I64x" #define OFF_FMT "%I64d" +#define PID_FMT "%d" #endif /* _NGX_TYPES_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_init.c b/src/os/win32/ngx_win32_init.c rename from src/os/win32/ngx_init.c rename to src/os/win32/ngx_win32_init.c --- a/src/os/win32/ngx_init.c +++ b/src/os/win32/ngx_win32_init.c @@ -2,15 +2,23 @@ #include #include +/* STUB */ +ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size); +ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in); +/* */ + +int ngx_win32_version; int ngx_max_sockets; +int ngx_inherited_nonblocking = 1; ngx_os_io_t ngx_os_io = { ngx_wsarecv, NULL, NULL, - NULL + ngx_wsasend_chain, + 0 }; @@ -26,7 +34,7 @@ static GUID tf_guid = WSAID_TRANSMITFILE int ngx_os_init(ngx_log_t *log) { - u_int sp; + u_int osviex; DWORD bytes; SOCKET s; WSADATA wsd; @@ -34,14 +42,14 @@ int ngx_os_init(ngx_log_t *log) /* get Windows version */ - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + ngx_memzero(&osvi, sizeof(OSVERSIONINFOEX)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); osviex = GetVersionEx((OSVERSIONINFO *) &osvi); if (osviex == 0) { osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) + if (GetVersionEx((OSVERSIONINFO *) &osvi) == 0) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "GetVersionEx() failed"); return NGX_ERROR; @@ -49,27 +57,36 @@ int ngx_os_init(ngx_log_t *log) } /* - * Windows 95 1400 - * Windows 98 1410 - * Windows ME 1490 - * Windows NT 3.51 2351 - * Windows NT 4.0 2400 - * Windows 2000 2500 - * Windows XP 2501 - * Windows 2003 2502 + * Windows 95 140000 + * Windows 98 141000 + * Windows ME 149000 + * Windows NT 3.51 235100 + * Windows NT 4.0 240000 + * Windows NT 4.0 SP5 240050 + * Windows 2000 250000 + * Windows XP 250100 + * Windows 2003 250200 */ - ngx_win32_version = osvi.dwPlatformId * 1000 - + osvi.dwMajorVersion * 100 - + osvi.dwMinorVersion; + ngx_win32_version = osvi.dwPlatformId * 100000 + + osvi.dwMajorVersion * 10000 + + osvi.dwMinorVersion * 100; if (osviex) { - sp = osvi.wServicePackMajor * 100 + osvi.wServicePackMinor; + ngx_win32_version += osvi.wServicePackMajor * 10 + + osvi.wServicePackMinor; ngx_log_error(NGX_LOG_INFO, log, 0, - "OS: %u build:%u, %s, SP:%u, suite:%x, type:%u", + "OS: %u build:%u, %s, suite:%x, type:%u", ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion, - sp, osvi.wSuiteMask, osvi.wProductType); + osvi.wReserved[0], osvi.wReserved[1]); + +#if 0 + ngx_log_error(NGX_LOG_INFO, log, 0, + "OS: %u build:%u, %s, suite:%x, type:%u", + ngx_win32_version, osvi.dwBuildNumber, osvi.szCSDVersion, + osvi.wSuiteMask, osvi.wProductType); +#endif } else { ngx_log_error(NGX_LOG_INFO, log, 0, "OS: %u build:%u, %s", diff --git a/src/os/win32/ngx_wsarecv.c b/src/os/win32/ngx_wsarecv.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_wsarecv.c @@ -0,0 +1,90 @@ + +#include +#include +#include + + +ssize_t ngx_wsarecv(ngx_connection_t *c, char *buf, size_t size) +{ + int rc; + u_int flags; + size_t bytes; + WSABUF wsabuf[1]; + ngx_err_t err; + ngx_event_t *rev; + LPWSAOVERLAPPED ovlp; + + rev = c->read; + bytes = 0; + + if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) && rev->ready) { + rev->ready = 0; + + /* the overlapped WSARecv() completed */ + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + if (rev->ovlp.error) { + ngx_log_error(NGX_LOG_ERR, c->log, rev->ovlp.error, + "WSARecv() failed"); + return NGX_ERROR; + } + + return rev->available; + } + + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &rev->ovlp, + &bytes, 0, NULL) == 0) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_CRIT, c->log, err, + "WSARecv() or WSAGetOverlappedResult() failed"); + + return NGX_ERROR; + } + + return bytes; + } + + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + ovlp = (LPWSAOVERLAPPED) &c->read->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + } else { + ovlp = NULL; + } + + wsabuf[0].buf = buf; + wsabuf[0].len = size; + flags = 0; + + rc = WSARecv(c->fd, wsabuf, 1, &bytes, &flags, ovlp, NULL); + + ngx_log_debug(c->log, "WSARecv: %d:%d" _ rc _ bytes); + + if (rc == -1) { + err = ngx_socket_errno; + if (err == WSA_IO_PENDING) { + return NGX_AGAIN; + + } else if (err == WSAEWOULDBLOCK) { + ngx_log_error(NGX_LOG_INFO, c->log, err, "WSARecv() EAGAIN"); + return NGX_AGAIN; + + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSARecv() failed"); + return NGX_ERROR; + } + } + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + + /* + * If a socket was bound with I/O completion port + * then GetQueuedCompletionStatus() would anyway return its status + * despite that WSARecv() was already completed. + */ + + return NGX_AGAIN; + } + + return bytes; +} diff --git a/src/os/win32/ngx_wsasend_chain.c b/src/os/win32/ngx_wsasend_chain.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_wsasend_chain.c @@ -0,0 +1,181 @@ + +#include +#include +#include + + +ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in) +{ + int rc; + char *prev; + size_t size, sent; + LPWSABUF wsabuf; + ngx_err_t err; + ngx_event_t *wev; + ngx_array_t wsabufs; + ngx_chain_t *ce; + LPWSAOVERLAPPED ovlp; + +#if 0 + +iocp: + if ready + get result + update chain + return if done; + wsasend + +non-block + for ( ;; ) { + wsasend + if no again + update chain + return if done; + } + + + for ( ;; ) { + + make buffers and limit data for both ovlp and nonblocked, + configured in events module + + if (iocp && ready) { + get result + + } else { + if (file) + transmitfile + else + wsasend + + if (iocp) + return chain + return chain if again + here is result + } + + if (result) + update chain; + return chain if done + } + } + + +#endif + + wev = c->write; + + if (((ngx_event_flags & NGX_HAVE_AIO_EVENT) && !wev->ready) + || ((ngx_event_flags & NGX_HAVE_AIO_EVENT) == 0)) + { + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + ngx_init_array(wsabufs, c->pool, 10, sizeof(WSABUF), NGX_CHAIN_ERROR); + + prev = NULL; + wsabuf = NULL; + + /* create the WSABUF and coalesce the neighbouring chain entries */ + for (ce = in; ce; ce = ce->next) { + + if (prev == ce->hunk->pos) { + wsabuf->len += ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + + } else { + ngx_test_null(wsabuf, ngx_push_array(&wsabufs), + NGX_CHAIN_ERROR); + wsabuf->buf = ce->hunk->pos; + wsabuf->len = ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + } + } + + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + } else { + ovlp = NULL; + } + + rc = WSASend(c->fd, wsabufs.elts, wsabufs.nelts, &sent, 0, ovlp, NULL); + + if (rc == -1) { + err = ngx_errno; + if (err == WSA_IO_PENDING) { + sent = 0; + + } else if (err == WSAEWOULDBLOCK) { + sent = 0; + ngx_log_error(NGX_LOG_INFO, c->log, err, "WSASend() EAGAIN"); + + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + } else { + + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + + /* + * If a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already completed. + */ + + sent = 0; + } + } + + } else { + if (ngx_event_flags & NGX_HAVE_IOCP_EVENT) { + wev->ready = 0; + + /* the overlapped WSASend() completed */ + + if (wev->ovlp.error) { + ngx_log_error(NGX_LOG_ERR, c->log, wev->ovlp.error, + "WSASend() failed"); + return NGX_CHAIN_ERROR; + } + + sent = wev->available; + } + } + +#if (NGX_DEBUG_WRITE_CHAIN) + ngx_log_debug(c->log, "WSASend(): %d" _ sent); +#endif + + c->sent += sent; + + for (ce = in; ce && sent > 0; ce = ce->next) { + + size = ce->hunk->last - ce->hunk->pos; + + if (sent >= size) { + sent -= size; + + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos = ce->hunk->last; + } + + continue; + } + + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos += sent; + } + + break; + } + + ngx_destroy_array(&wsabufs); + + return ce; +}