# HG changeset patch # User Igor Sysoev # Date 1052754744 0 # Node ID 3973260705cc12408c1268e8c545e68de1e0c2ff # Parent 3549c2bf9eaff1e5fe3569411f14a7724f6e0247 nginx-0.0.1-2003-05-12-19:52:24 import diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -67,6 +67,10 @@ int main(int argc, char *const *argv) #endif + if (ngx_os_init(&ngx_log) == NGX_ERROR) { + exit(1); + } + ngx_init_array(ngx_listening_sockets, ngx_pool, 10, sizeof(ngx_listen_t), 1); 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 @@ -141,7 +141,7 @@ int ngx_kqueue_del_event(ngx_event_t *ev if (nchanges > 0 && ev->index < nchanges - && change_list[ev->index].udata == ev) + && (void *) ((uintptr_t) change_list[ev->index].udata & ~1) == ev) { #if (NGX_DEBUG_EVENT) ngx_connection_t *c = (ngx_connection_t *) ev->data; @@ -159,8 +159,9 @@ int ngx_kqueue_del_event(ngx_event_t *ev return NGX_OK; } - /* when a socket is closed kqueue automatically deletes its filters - so we do not need to delete a event explicity before a socket closing */ + /* when the file descriptor is closed a kqueue automatically deletes + its filters so we do not need to delete explicity the event + before the closing the file descriptor */ if (flags & NGX_CLOSE_EVENT) { return NGX_OK; @@ -200,7 +201,7 @@ int ngx_kqueue_set_event(ngx_event_t *ev change_list[nchanges].ident = c->fd; change_list[nchanges].filter = filter; change_list[nchanges].flags = flags; - change_list[nchanges].udata = ev; + change_list[nchanges].udata = (void *) ((uintptr_t) ev | ev->instance); #if (HAVE_LOWAT_EVENT) @@ -230,7 +231,7 @@ int ngx_kqueue_set_event(ngx_event_t *ev int ngx_kqueue_process_events(ngx_log_t *log) { - int events, i; + int events, instance, i; ngx_msec_t timer, delta; ngx_event_t *ev; struct timeval tv; @@ -310,12 +311,15 @@ int ngx_kqueue_process_events(ngx_log_t } ev = (ngx_event_t *) event_list[i].udata; + instance = (uintptr_t) ev & 1; + ev = (void *) ((uintptr_t) ev & ~1); - /* It's a stale event from a socket + /* It's a stale event from a file descriptor that was just closed in this iteration */ - if (!ev->active) { - continue; + if (ev->active == 0 || ev->instance != instance) { + ngx_log_debug(log, "stale kevent"); + continue; } switch (event_list[i].filter) { @@ -323,28 +327,6 @@ int ngx_kqueue_process_events(ngx_log_t case EVFILT_READ: case EVFILT_WRITE: - if (ev->first) { - if (nchanges > 0 - && ev->index < nchanges - && change_list[ev->index].udata == ev) { - - /* It's a stale event from a socket that was just closed - in this iteration and during processing another socket - was opened with the same number by accept() or socket() - and its event has been added the event to the change_list - but has not been passed to a kernel. Nevertheless - there's small chance that ngx_kqueue_set_event() has - flushed the new event if the change_list was filled up. - In this very rare case we would get EAGAIN while - a reading or a writing */ - - continue; - - } else { - ev->first = 0; - } - } - ev->available = event_list[i].data; if (event_list[i].flags & EV_EOF) { 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 @@ -63,7 +63,9 @@ struct ngx_event_s { #endif unsigned write:1; - unsigned first:1; + unsigned instance:1; /* used to detect stale events in kqueue, + rt signals and epoll */ + unsigned active:1; unsigned ready:1; unsigned timedout:1; @@ -114,6 +116,7 @@ struct ngx_event_s { #endif }; + typedef enum { NGX_SELECT_EVENT_N = 0, #if (HAVE_POLL) 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 @@ -16,6 +16,7 @@ int ngx_event_accept(ngx_event_t *ev) { + int instance; socklen_t len; struct sockaddr *sa; ngx_err_t err; @@ -95,6 +96,8 @@ int ngx_event_accept(ngx_event_t *ev) wev = &ngx_write_events[s]; c = &ngx_connections[s]; + instance = rev->instance; + ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); ngx_memzero(c, sizeof(ngx_connection_t)); @@ -108,6 +111,8 @@ int ngx_event_accept(ngx_event_t *ev) c->addr_text_max_len = ls->addr_text_max_len; c->post_accept_timeout = ls->post_accept_timeout; + rev->instance = wev->instance = !instance; + rev->index = wev->index = NGX_INVALID_INDEX; rev->data = wev->data = c; @@ -117,7 +122,6 @@ int ngx_event_accept(ngx_event_t *ev) c->fd = s; c->unexpected_eof = 1; wev->write = 1; - rev->first = wev->first = 1; #if (USE_KQUEUE) wev->ready = 1; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_connect.c @@ -0,0 +1,126 @@ + +#include + + +int ngx_event_connect_peer(ngx_connect_peer_t *cp) +{ + + + if (cp->peers->number > 1) { + + /* it's a first try - get current peer */ + + if (cp->tries == cp->peers->number) { + + /* Here is the race condition + when the peers are shared between + the threads or the processes but it should not be serious */ + + cp->cur_peer = cp->peers->current++; + + if (cp->peers->current >= cp->peers->number) { + cp->peers->current = 0; + } + + /* */ + +#if (NGX_MULTITHREADED || NGX_MULTIPROCESSED) + /* eliminate the sequences of the race condition */ + if (cp->cur_peer >= cp->peers->number) { + cp->cur_peer = 0; + } +#endif + } + + if (cp->peers->max_fails > 0) { + + for ( ;; ) { + peer = &cp->peers->peers[cp->cur_peer]; + + /* Here is the race condition + when the peers are shared between + the threads or the processes but it should not be serious */ + + if (peer->fails <= cp->peers->max_fails + || (now - peer->accessed > cp->peers->fail_timeout)) + { + break; + } + + /* */ + + cp->cur_peer++; + + if (cp->cur_peer >= cp->peers->number) { + cp->cur_peer = 0; + } + + cp->tries--; + + if (cp->tries == 0) { + return NGX_ERROR; + } + } + } + } + + + + + + s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0); + + if (s == -1) { + ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno, + ngx_socket_n " failed"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (cn->rcvbuf) { + if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, + (const void *) &cn->rcvbuf, sizeof(int)) == -1) { + ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno, + "setsockopt(SO_RCVBUF) failed"); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno, + ngx_nonblocking_n " failed"); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, cn->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + c = &ngx_connections[s]; + rev = &ngx_read_events[s]; + wev = &ngx_write_events[s]; + + instance = rev->instance; + + ngx_memzero(c, sizeof(ngx_connection_t)); + ngx_memzero(rev, sizeof(ngx_event_t)); + ngx_memzero(wev, sizeof(ngx_event_t)); + + rev->index = wev->index = NGX_INVALID_INDEX; + rev->data = wev->data = c; + c->read = rev; + c->write = wev; + + rev->instance = wev->instance = !instance; + + rev->log = wev->log = c->log = cn->log; + c->fd = s; + wev->close_handler = rev->close_handler = ngx_event_close_connection; + diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_connect.h @@ -0,0 +1,43 @@ +#ifndef _NGX_EVENT_CONNECT_H_INCLUDED_ +#define _NGX_EVENT_CONNECT_H_INCLUDED_ + + +#include +#include +#include +#include +#include + + +typedef struct { + u_int32_t addr; + ngx_str_t host; + int port; + ngx_str_t addr_port_name; + + int fails; + time_t accessed; +} ngx_peer_t; + + +typedef struct { + int current; + int number; + int max_fails; + int fail_timeout; + + /* ngx_mutex_t *mutex; */ + /* ngx_connection_t *cached; */ + + ngx_peer_t peers[1]; +} ngx_peers_t; + + +typedef struct { + ngx_peers_t *peers; + int cur_peer; + int tries; +} ngx_connect_peer_t; + + +#endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */ 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 @@ -45,7 +45,8 @@ void ngx_event_add_timer(ngx_event_t *ev #if (NGX_DEBUG_EVENT) ngx_connection_t *c = (ngx_connection_t *) ev->data; - ngx_log_debug(ev->log, "set timer: %d:%d" _ c->fd _ timer); + ngx_log_debug(ev->log, "set timer: %d:%d, slot: %d" _ + c->fd _ timer _ ngx_timer_cur_queue); #endif if (ev->timer_next || ev->timer_prev) { @@ -53,10 +54,6 @@ void ngx_event_add_timer(ngx_event_t *ev return; } -#if (NGX_DEBUG_EVENT) - ngx_log_debug(ev->log, "timer slot: %d" _ ngx_timer_cur_queue); -#endif - for (e = ngx_timer_queue[ngx_timer_cur_queue].timer_next; e != &ngx_timer_queue[ngx_timer_cur_queue] && timer > e->timer_delta; e = e->timer_next) diff --git a/src/http/modules/proxy/ngx_http_event_proxy_handler.c b/src/http/modules/proxy/ngx_http_event_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_event_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_event_proxy_handler.c @@ -481,7 +481,7 @@ static int ngx_http_proxy_process_upstre static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) { - int rc, event; + int rc, event, instance; struct sockaddr_in *addr; ngx_err_t err; ngx_socket_t s; @@ -590,6 +590,8 @@ static int ngx_http_proxy_connect(ngx_ht rev = &ngx_read_events[s]; wev = &ngx_write_events[s]; + instance = rev->instance; + ngx_memzero(c, sizeof(ngx_connection_t)); ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); @@ -598,7 +600,9 @@ static int ngx_http_proxy_connect(ngx_ht rev->data = wev->data = c; c->read = rev; c->write = wev; - rev->first = wev->first = 1; + + rev->instance = wev->instance = !instance; + rev->log = wev->log = c->log = p->log; c->fd = s; wev->close_handler = rev->close_handler = ngx_event_close_connection; @@ -1002,7 +1006,7 @@ static int ngx_http_proxy_process_upstre r = p->request; for ( ;; ) { - rc = ngx_read_http_header_line(r, p->header_in); + rc = ngx_parse_http_header_line(r, p->header_in); /* a header line has been parsed successfully */ 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 @@ -231,9 +231,9 @@ typedef int (*ngx_http_output_body_filte int ngx_http_init(ngx_pool_t *pool, ngx_log_t *log); /**/ -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); +void ngx_http_init_connection(ngx_connection_t *c); +int ngx_parse_http_request_line(ngx_http_request_t *r); +int ngx_parse_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h); int ngx_http_handler(ngx_http_request_t *r); 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 @@ -568,9 +568,9 @@ int ngx_http_close_request(ngx_http_requ c->write->timer_set = 0; } - ngx_log_debug(c->log, "http closed"); + ngx_log_debug(c->log, "http request closed"); - return NGX_ERROR; /* to close connection */ + return 0; } 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 @@ -18,10 +18,17 @@ #include -static int ngx_http_init_request(ngx_event_t *ev); +static void ngx_http_init_request(ngx_event_t *ev); +static void ngx_http_process_request_line(ngx_event_t *rev); +static void ngx_http_process_request_headers(ngx_event_t *rev); + + + +static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); + + + static int ngx_http_process_request(ngx_event_t *ev); -static int ngx_http_process_request_line(ngx_http_request_t *r); -static int ngx_http_process_request_headers(ngx_http_request_t *r); static int ngx_http_process_request_header_line(ngx_http_request_t *r); static int ngx_http_request_handler(ngx_http_request_t *r, int error); @@ -33,11 +40,12 @@ static int ngx_http_keepalive_handler(ng static int ngx_http_set_lingering_close(ngx_http_request_t *r); static int ngx_http_lingering_close_handler(ngx_event_t *ev); -static int ngx_http_close_connection(ngx_event_t *ev); +static int ngx_http_close_connection(ngx_connection_t *c); static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err); static size_t ngx_http_log_error(void *data, char *buf, size_t len); +/* NGX_HTTP_PARSE_ ... errors */ static char *header_errors[] = { "client %s sent invalid method", @@ -67,127 +75,142 @@ static ngx_http_header_t headers_in[] = }; -int ngx_http_init_connection(ngx_connection_t *c) +void ngx_http_init_connection(ngx_connection_t *c) { + int event; ngx_event_t *rev; - ngx_http_log_ctx_t *ctx; + ngx_http_log_ctx_t *lcx; + + c->addr_text.data = ngx_palloc(c->pool, c->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); + if (c->addr_text.len == 0) { + ngx_http_close_connection(c); + return; + } + + lcx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)); + if (lcx == NULL) { + ngx_http_close_connection(c); + return; + } + + lcx->client = c->addr_text.data; + lcx->action = "reading client request line"; + c->log->data = lcx; + c->log->handler = ngx_http_log_error; rev = c->read; rev->event_handler = ngx_http_init_request; - rev->close_handler = ngx_http_close_connection; - c->write->close_handler = ngx_http_close_connection; - - ngx_test_null(c->addr_text.data, ngx_palloc(c->pool, c->addr_text_max_len), - NGX_ERROR); - - c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr, - c->addr_text.data, c->addr_text_max_len); - - if (c->addr_text.len == 0) { - return NGX_ERROR; + if (rev->ready) { + /* deferred accept */ + ngx_http_init_request(rev); + return; } - ngx_test_null(ctx, ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)), - NGX_ERROR); - ctx->client = c->addr_text.data; - ctx->action = "reading client request line"; - c->log->data = ctx; - c->log->handler = ngx_http_log_error; - -#if (HAVE_DEFERRED_ACCEPT) - - if (rev->ready) { - return ngx_http_init_request(rev); - } - -#endif - ngx_add_timer(rev, c->post_accept_timeout); rev->timer_set = 1; -#if (USE_KQUEUE) - - return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT); - -#else - - /* kqueue */ - - if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { - return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT); + if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) { + /* aio, iocp, epoll */ + ngx_http_init_request(rev); + return; } - /* aio, iocp, epoll */ + if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { + /* kqueue */ + event = NGX_CLEAR_EVENT; - if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) { - return ngx_http_init_request(rev); + } else { + /* select, poll, /dev/poll */ + event = NGX_LEVEL_EVENT; } - /* select, poll, /dev/poll */ + if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) { + ngx_http_close_connection(c); + } - return ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT); - -#endif /* USE_KQUEUE */ + return; } -static int ngx_http_init_request(ngx_event_t *rev) +static void ngx_http_init_request(ngx_event_t *rev) { ngx_connection_t *c; ngx_http_request_t *r; ngx_http_conf_ctx_t *ctx; c = (ngx_connection_t *) rev->data; - c->sent = 0; - - ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)), - NGX_ERROR); - - c->data = r; - r->connection = c; - r->file.fd = NGX_INVALID_FILE; if (c->buffer == NULL) { - ngx_test_null(c->buffer, - ngx_create_temp_hunk(c->pool, - ngx_http_client_header_buffer_size, - 0, 0), - NGX_ERROR); - } else { - r->header_read = 1; + c->buffer = ngx_create_temp_hunk(c->pool, + ngx_http_client_header_buffer_size, + 0, 0); + if (c->buffer == NULL) { + ngx_http_close_connection(c); + return; + } + } + + r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); + if (r == NULL) { + ngx_http_close_connection(c); + return; } - r->pipeline = c->pipeline; - r->header_in = c->buffer; + r->pool = ngx_create_pool(ngx_http_request_pool_size, c->log); + if (r->pool == NULL) { + ngx_http_close_connection(c); + return; + } - ngx_test_null(r->pool, ngx_create_pool(ngx_http_request_pool_size, c->log), - NGX_ERROR); + r->headers_out.headers = ngx_create_table(r->pool, 10); + if (r->headers_out.headers == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } - ngx_test_null(r->ctx, - ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module), - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR)); + r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); + if (r->ctx == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ctx = (ngx_http_conf_ctx_t *) c->ctx; r->srv_conf = ctx->srv_conf; r->loc_conf = ctx->loc_conf; + c->sent = 0; + c->data = r; + r->connection = c; + r->pipeline = c->pipeline; + r->header_in = c->buffer; + + r->file.fd = NGX_INVALID_FILE; + r->headers_in.content_length_n = -1; - r->headers_out.headers = ngx_create_table(r->pool, 10); r->headers_out.content_length = -1; r->headers_out.last_modified_time = -1; - rev->event_handler = ngx_http_process_request; - r->state_handler = ngx_http_process_request_line; + rev->event_handler = ngx_http_process_request_line; + ngx_http_process_request_line(rev); - return ngx_http_process_request(rev); + return; } -static int ngx_http_process_request(ngx_event_t *rev) +static void ngx_http_process_request_line(ngx_event_t *rev) { - int n, rc; - ngx_event_t *wev; + int rc, offset; + ssize_t n; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_log_ctx_t *lcx; @@ -195,139 +218,35 @@ static int ngx_http_process_request(ngx_ c = (ngx_connection_t *) rev->data; r = (ngx_http_request_t *) c->data; - ngx_log_debug(c->log, "http process request"); + ngx_log_debug(rev->log, "http process request line"); if (rev->timedout) { - return ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); + ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); + ngx_http_close_connection(c); + return; } - do { - - if (r->header_read) { - r->header_read = 0; - ngx_log_debug(c->log, "http preread %d" _ - r->header_in->last - r->header_in->pos); - - } else { - n = ngx_event_recv(c, r->header_in->last, - r->header_in->end - r->header_in->last); - - if (n == NGX_AGAIN) { - if (!r->header_timeout_set) { - - if (rev->timer_set) { - ngx_del_timer(rev); - } else { - rev->timer_set = 1; - } - - ngx_add_timer(rev, ngx_http_client_header_timeout); - r->header_timeout_set = 1; - } - - return NGX_AGAIN; - } - - if (n == NGX_ERROR) { - return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST); - } - - ngx_log_debug(c->log, "http read %d" _ n); - - if (n == 0) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client closed prematurely connection"); - return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST); - } - - r->header_in->last += n; - } + n = ngx_http_read_request_header(r); - /* the state handlers are called in the following order: - ngx_http_process_request_line(r) - ngx_http_process_request_headers(r) */ - - do { - rc = r->state_handler(r); - - } while (rc == NGX_AGAIN && r->header_in->pos < r->header_in->last); - - } while (rc == NGX_AGAIN - && (rev->ready || ngx_event_flags & NGX_HAVE_AIO_EVENT)); - - if (rc >= NGX_OK) { - - /* HTTP header done */ - - rev->event_handler = ngx_http_block_read; - - if (rc != NGX_OK) { - return ngx_http_finalize_request(r, rc); - } - - lcx = c->log->data; - lcx->action = "processing client request"; - -#if 0 - wev = c->write; - ngx_add_timer(wev, 5000); - wev->delayed = 1; - wev->timer_set = 1; -#endif - - rc = ngx_http_handler(r); - - /* a handler does its own processing */ - if (rc == NGX_DONE) { - return rc; - } - - if (rc == NGX_ERROR) { - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - return ngx_http_finalize_request(r, rc); - + if (n == NGX_AGAIN || n == NGX_ERROR) { + return; } - /* NGX_AGAIN */ - - if (!r->header_timeout_set) { - - if (rev->timer_set) { - ngx_del_timer(rev); - } else { - rev->timer_set = 1; - } - - ngx_add_timer(rev, ngx_http_client_header_timeout); - r->header_timeout_set = 1; - } - - return rc; -} - - -static int ngx_http_process_request_line(ngx_http_request_t *r) -{ - int rc, offset; - ngx_connection_t *c; - ngx_http_log_ctx_t *lcx; - - rc = ngx_read_http_request_line(r); - - c = r->connection; - - /* a request line has been parsed successfully */ + rc = ngx_parse_http_request_line(r); if (rc == NGX_OK) { + /* the request line has been parsed successfully */ + if (r->http_version >= NGX_HTTP_VERSION_10 && ngx_http_large_client_header == 0 && r->header_in->pos == r->header_in->end) { + /* no space for "\r\n" at the end of the header */ + ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI); - return NGX_HTTP_REQUEST_URI_TOO_LARGE; + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); + return; } /* copy URI */ @@ -338,20 +257,28 @@ static int ngx_http_process_request_line r->uri.len = r->uri_end - r->uri_start; } - ngx_test_null(r->uri.data, ngx_palloc(r->pool, r->uri.len + 1), - NGX_HTTP_INTERNAL_SERVER_ERROR); + r->uri.data = ngx_palloc(r->pool, r->uri.len + 1); + if (r->uri.data == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1); r->request_line.len = r->request_end - r->request_start; - /* if the large client headers are enabled then + /* if the large client header is enabled then we need to copy a request line */ if (ngx_http_large_client_header) { - ngx_test_null(r->request_line.data, - ngx_palloc(r->pool, r->request_line.len + 1), - NGX_HTTP_INTERNAL_SERVER_ERROR); + + r->request_line.data = ngx_palloc(r->pool, r->request_line.len + 1); + if (r->request_line.data == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ngx_cpystrn(r->request_line.data, r->request_start, r->request_line.len + 1); @@ -370,9 +297,12 @@ static int ngx_http_process_request_line r->exten.len = r->uri_end - r->uri_ext; } - ngx_test_null(r->exten.data, - ngx_palloc(r->pool, r->exten.len + 1), - NGX_HTTP_INTERNAL_SERVER_ERROR); + r->exten.data = ngx_palloc(r->pool, r->exten.len + 1); + if (r->exten.data == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1); } @@ -382,67 +312,59 @@ static int ngx_http_process_request_line if (r->args_start && r->uri_end > r->args_start) { r->args.len = r->uri_end - r->args_start; - ngx_test_null(r->args.data, - ngx_palloc(r->pool, r->args.len + 1), - NGX_HTTP_INTERNAL_SERVER_ERROR); + r->args.data = ngx_palloc(r->pool, r->args.len + 1); + if (r->args.data == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1); } -#if 1 - if (r->exten.data == NULL) { - r->exten.data = ""; - } - if (r->args.data == NULL) { - r->args.data = ""; - } - ngx_log_debug(r->connection->log, "HTTP: %d, %d, '%s', '%s', '%s'" _ +#if 1 /* DEBUG */ + if (r->exten.data == NULL) { r->exten.data = ""; } + if (r->args.data == NULL) { r->args.data = ""; } + ngx_log_debug(c->log, "HTTP: %d, %d, '%s', '%s', '%s'" _ r->method _ r->http_version _ r->uri.data _ r->exten.data _ r->args.data); - if (r->exten.data[0] == '\0') { - r->exten.data = NULL; - } - if (r->args.data[0] == '\0') { - r->args.data = NULL; - } + if (r->exten.data[0] == '\0') { r->exten.data = NULL; } + if (r->args.data[0] == '\0') { r->args.data = NULL; } #endif - lcx = r->connection->log->data; + lcx = c->log->data; if (ngx_http_url_in_error_log) { - ngx_test_null(lcx->url, - ngx_palloc(r->pool, r->uri_end - r->uri_start + 1), - NGX_HTTP_INTERNAL_SERVER_ERROR); + lcx->url = ngx_palloc(r->pool, r->uri_end - r->uri_start + 1); + if (lcx->url == NULL) { + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(c); + return; + } ngx_cpystrn(lcx->url, r->uri_start, r->uri_end - r->uri_start + 1); } - /* if we need to parse the headers then return NGX_AGAIN - becuase of HTTP/0.9 has no headers so return NGX_OK */ - if (r->http_version == NGX_HTTP_VERSION_9) { - r->state_handler = NULL; - return NGX_OK; + /* STUB */ return; } + lcx->action = "reading client request headers"; r->headers_in.headers = ngx_create_table(r->pool, 10); - r->state_handler = ngx_http_process_request_headers; - lcx->action = "reading client request headers"; - if (ngx_http_large_client_header && r->header_in->pos == r->header_in->last) { r->header_in->pos = r->header_in->last = r->header_in->start; } - return NGX_AGAIN; + } else if (rc != NGX_AGAIN) { - /* there was error while a request line parsing */ + /* there was error while a request line parsing */ - } else if (rc != NGX_AGAIN) { ngx_http_header_parse_error(r, rc); - return NGX_HTTP_BAD_REQUEST; + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; } /* NGX_AGAIN: a request line parsing is still not complete */ @@ -450,17 +372,18 @@ static int ngx_http_process_request_line if (r->header_in->last == r->header_in->end) { /* If it's a pipelined request and a request line is not complete - then we need to copy it to the start of r->header_in hunk. + then we need to copy it to the start of the r->header_in hunk. We need to copy it here only if the large client headers are enabled otherwise a request line had been already copied - to the start of r->header_in hunk in ngx_http_set_keepalive() */ + to the start of the r->header_in hunk in ngx_http_set_keepalive() */ if (ngx_http_large_client_header) { offset = r->request_start - r->header_in->start; if (offset == 0) { ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI); - return NGX_HTTP_REQUEST_URI_TOO_LARGE; + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); + return; } ngx_memcpy(r->header_in->start, r->request_start, @@ -481,22 +404,41 @@ static int ngx_http_process_request_line } else { ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI); - return NGX_HTTP_REQUEST_URI_TOO_LARGE; + ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE); + return; } } - return NGX_AGAIN; + rev->event_handler = ngx_http_process_request_headers; + ngx_http_process_request_headers(rev); + + return; } -static int ngx_http_process_request_headers(ngx_http_request_t *r) +static void ngx_http_process_request_headers(ngx_event_t *rev) { int rc, offset; size_t len; + ssize_t n; + ngx_connection_t *c; + ngx_http_request_t *r; ngx_http_log_ctx_t *ctx; + if (rev->timedout) { + ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT); + ngx_http_close_connection(c); + return; + } + + n = ngx_http_read_request_header(r); + + if (n == NGX_AGAIN || n == NGX_ERROR) { + return; + } + for ( ;; ) { - rc = ngx_read_http_header_line(r, r->header_in); + rc = ngx_parse_http_header_line(r, r->header_in); /* a header line has been parsed successfully */ @@ -792,6 +734,53 @@ static int ngx_http_writer(ngx_event_t * } +static ssize_t ngx_http_read_request_header(ngx_http_request_t *r) +{ + ssize_t n; + ngx_event_t *rev; + + n = r->header_in->last - r->header_in->pos; + + if (n > 0) { + return n; + } + + n = ngx_event_recv(r->connection, r->header_in->last, + r->header_in->end - r->header_in->last); + + if (n == NGX_AGAIN) { + if (!r->header_timeout_set) { + rev = r->connection->read; + + if (rev->timer_set) { + ngx_del_timer(rev); + } else { + rev->timer_set = 1; + } + + ngx_add_timer(rev, ngx_http_client_header_timeout); + r->header_timeout_set = 1; + } + + return NGX_AGAIN; + } + + if (n == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client closed prematurely connection"); + + if (n == 0 || n == NGX_ERROR) { + ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST); + ngx_http_close_connection(c); + return NGX_ERROR; + } + + r->header_in->last += n; + + return n; +} + + static int ngx_http_block_read(ngx_event_t *ev) { ngx_log_debug(ev->log, "http read blocked"); @@ -1144,7 +1133,46 @@ static int ngx_http_lingering_close_hand } -static int ngx_http_close_connection(ngx_event_t *ev) +static void ngx_http_close_connection(ngx_connection_t *c) +{ + ngx_log_debug(c->log, "close connection: %d" _ c->fd); + + if (c->fd == -1) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed"); + return; + } + + if (c->read->timer_set) { + ngx_del_timer(c->read); + c->read->timer_set = 0; + } + + if (c->read->active) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + c->write->timer_set = 0; + } + + if (c->write->active) { + ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); + } + + if (ngx_close_socket(c->fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + c->fd = -1; + + ngx_destroy_pool(c->pool); + + return; +} + +static int ngx_http_close_connection0(ngx_event_t *ev) { return ngx_event_close_connection(ev); } 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 @@ -3,7 +3,7 @@ #include #include -int ngx_read_http_request_line(ngx_http_request_t *r) +int ngx_parse_http_request_line(ngx_http_request_t *r) { char ch; char *p; @@ -326,7 +326,7 @@ int ngx_read_http_request_line(ngx_http_ } } -int ngx_read_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h) +int ngx_parse_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h) { char c, ch; char *p; diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_daemon.c @@ -0,0 +1,80 @@ + +#include +#include +#include + +/* daemon in Linux */ + +int ngx_daemon(ngx_log_t *log) +{ + int fd; + + switch (fork()) { + case -1: + ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed"); + return NGX_ERROR; + + case 0: + break; + + default: + exit(0); + } + + if (setsid() == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "setsid() failed"); + return NGX_ERROR; + } + +#if (__SVR4 || linux) + + /* need HUP IGN ? check in Solaris and Linux */ + + switch (fork()) { + case -1: + ngx_log_error(NGX_LOG_ALERT, log, errno, "fork() failed"); + return NGX_ERROR; + + case 0: + break; + + default: + exit(0); + } + +#endif + + umask(0); + +#if 0 + fd = open("/dev/null", O_RDWR); + if (fd == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "open(\"/dev/null\") failed"); + return NGX_ERROR; + } + + if (dup2(fd, STDIN_FILENO) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDIN) failed"); + return NGX_ERROR; + } + + if (dup2(fd, STDOUT_FILENO) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDOUT) failed"); + return NGX_ERROR; + } + + if (dup2(fd, STDERR_FILENO) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "dup2(STDERR) failed"); + return NGX_ERROR; + } + + if (fd > STDERR_FILENO) { + if (close(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, "close() failed"); + return NGX_ERROR; + } + } +#endif + + return NGX_OK; +} diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_freebsd_init.c @@ -0,0 +1,67 @@ + +#include + + +int freebsd_kern_osreldate; +int freebsd_hw_ncpu; + +int freebsd_sendfile_nbytes_bug; + + +int ngx_os_init(ngx_log_t *log) +{ + size_t size; + + size = 4; + if (sysctlbyname("kern.osreldate", + &freebsd_kern_osreldate, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, + "sysctlbyname(kern.osreldate) failed"); + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "kern.osreldate: %d, built on %d", + freebsd_kern_osreldate, __FreeBSD_version); + + +#if HAVE_FREEBSD_SENDFILE + + /* The determination of the sendfile() nbytes bug is complex enough. + There're two sendfile() syscalls: a new 393 has no bug while + an old 336 has the bug in some versions and has not in others. + libc_r wrapper also emulates the bug in some versions. + There's no way to say exactly if a given FreeBSD version has bug. + Here is the algorithm that work at least for RELEASEs + and for syscalls only (not libc_r wrapper). */ + + /* detect was the new sendfile() version available at the compile time + to allow an old binary to run correctly on an updated FreeBSD system. */ + +#if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \ + || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039 + + /* a new syscall without the bug */ + freebsd_sendfile_nbytes_bug = 0; + +#else + + /* an old syscall that can have the bug */ + freebsd_sendfile_nbytes_bug = 1; + +#endif + +#endif /* HAVE_FREEBSD_SENDFILE */ + + + size = 4; + if (sysctlbyname("hw.ncpu", &freebsd_hw_ncpu, &size, NULL, 0) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, + "sysctlbyname(hw.ncpu) failed"); + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, "hw.ncpu: %d", freebsd_hw_ncpu); + + return NGX_OK; +} diff --git a/src/os/unix/ngx_freebsd_init.h b/src/os/unix/ngx_freebsd_init.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_freebsd_init.h @@ -0,0 +1,18 @@ +#ifndef _NGX_OS_INIT_H_INCLUDED_ +#define _NGX_OS_INIT_H_INCLUDED_ + + +#include +#include +#include +#include + + +int ngx_os_init(ngx_log_t *log); + + +extern int freebsd_kern_osreldate; +extern int freebsd_hw_ncpu; + + +#endif /* _NGX_OS_INIT_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c --- a/src/os/unix/ngx_freebsd_rfork_thread.c +++ b/src/os/unix/ngx_freebsd_rfork_thread.c @@ -11,57 +11,76 @@ extern int __isthreaded; typedef int ngx_tid_t; -#define NGX_MAX_THREADS 10 - static inline int ngx_gettid(); -static char *stacks_start; -static char *stacks_end; -static size_t stack_size; -static char *last_stack; -static int last_thread; - -static ngx_log_t *log; - -static ngx_tid_t tids[NGX_MAX_THREADS]; - +static char *usrstack; static int red_zone = 4096; +static size_t stack_size; +static size_t usable_stack_size; +static char *last_stack; + +static int threads; +static int nthreads; +static ngx_tid_t *tids; /* the thread-safe errno */ -static int errnos[NGX_MAX_THREADS]; +static int errno0; /* the main thread's errno */ +static int *errnos; int *__error() { - return &errnos[ngx_gettid()]; + int tid; + + tid = ngx_gettid(); + + return tid ? &errnos[tid - 1] : &errno0; } -int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg) +int ngx_create_thread(ngx_tid_t *tid, int (*func)(void *arg), void *arg, + ngx_log_t *log) { int id, err; - char *stack_top; + char *stack, *stack_top; - last_stack += stack_size; - stack_top = last_stack - red_zone; - - if (stack_top > stacks_end) { - ngx_log_error(NGX_LOG_CRIT, log, 0, "no more threads allocated"); + if (threads >= nthreads) { + ngx_log_error(NGX_LOG_CRIT, log, 0, + "no more than %d threads can be created", nthreads); return NGX_ERROR; } -#if 0 - id = rfork(RFFDG|RFCFDG); -#elif 0 + last_stack -= stack_size; + stack = mmap(last_stack, usable_stack_size, PROT_READ|PROT_WRITE, + MAP_STACK, -1, 0); + if (stack == MAP_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, errno, + "mmap(%08X:%d, MAP_STACK) thread stack failed", + last_stack, usable_stack_size); + return NGX_ERROR; + } + + if (stack != last_stack) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "stack address was changed"); + } + + stack_top = stack + usable_stack_size; + +printf("stack: %08X-%08X\n", stack, stack_top); + +#if 1 + id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); +#elif 1 + id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg); +#elif 1 id = rfork_thread(RFFDG|RFCFDG, stack_top, func, arg); -#elif 0 - id = rfork_thread(RFPROC|RFMEM, stack_top, func, arg); #else - id = rfork_thread(RFPROC|RFTHREAD|RFMEM, stack_top, func, arg); + id = rfork(RFFDG|RFCFDG); #endif + err = errno; if (id == -1) { @@ -69,7 +88,8 @@ int ngx_create_thread(ngx_tid_t *tid, in } else { *tid = id; - tids[last_thread++] = id; + threads = (usrstack - stack_top) / stack_size; + tids[threads] = id; /* allow the spinlock in libc malloc() */ __isthreaded = 1; @@ -79,14 +99,12 @@ int ngx_create_thread(ngx_tid_t *tid, in } -int ngx_init_thread_env(int n, size_t size, ngx_log_t *lg) +int ngx_init_thread_env(int n, size_t size, ngx_log_t *log) { - int len, i; - char *usrstack, *zone; + int len; + char *rz, *zone; - log = lg; - - /* create the thread stacks */ + nthreads = n; len = 4; if (sysctlbyname("kern.usrstack", &usrstack, &len, NULL, 0) == -1) { @@ -96,41 +114,37 @@ int ngx_init_thread_env(int n, size_t si } printf("usrstack: %08X\n", usrstack); -printf("red zone: %08X\n", usrstack - (size + red_zone)); + + /* red zone */ + rz = usrstack - (size + red_zone); -#if 1 - /* red zone */ - zone = mmap(usrstack - (size + red_zone), red_zone, - PROT_NONE, MAP_ANON, -1, 0); +printf("red zone: %08X\n", rz); + + zone = mmap(rz, red_zone, PROT_NONE, MAP_ANON, -1, 0); if (zone == MAP_FAILED) { ngx_log_error(NGX_LOG_ALERT, log, errno, - "mmap(%d, PROT_NONE, MAP_ANON) failed", red_zone); + "mmap(%08X:%d, PROT_NONE, MAP_ANON) red zone failed", + rz, red_zone); return NGX_ERROR; } -#else - zone = usrstack - (size + red_zone); -#endif + + if (zone != rz) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "red zone address was changed"); + } + + /* create the thread errno array */ + ngx_test_null(errnos, ngx_calloc(n * sizeof(int), log), NGX_ERROR); + + /* create the thread tid array */ + ngx_test_null(tids, ngx_calloc((n + 1) * sizeof(ngx_tid_t), log), + NGX_ERROR); + + tids[0] = ngx_getpid(); + threads = 1; last_stack = zone + red_zone; - - for (i = 0; i < n; i++) { - last_stack -= size + red_zone; -printf("stack: %08X\n", last_stack); - last_stack = mmap(last_stack, size, PROT_READ|PROT_WRITE, - MAP_STACK, -1, 0); - if (last_stack == MAP_FAILED) { - ngx_log_error(NGX_LOG_ALERT, log, errno, - "mmap(%d, MAP_STACK) failed", size); - return NGX_ERROR; - } - } - - stacks_start = last_stack; + usable_stack_size = size; stack_size = size + red_zone; - stacks_end = stacks_start + n * stack_size; - - tids[0] = ngx_getpid(); - last_thread = 1; return NGX_OK; } @@ -138,7 +152,18 @@ printf("stack: %08X\n", last_stack); ngx_tid_t ngx_thread_self() { - return tids[ngx_gettid()]; + int tid; + ngx_tid_t pid; + + tid = ngx_gettid(); + + if (tids[tid] == 0) { + pid = ngx_getpid(); + tids[tid] = pid; + return pid; + } + + return tids[tid]; } @@ -146,7 +171,11 @@ static inline int ngx_gettid() { char *sp; + if (stack_size == 0) { + return 0; + } + __asm__ ("mov %%esp, %0" : "=q" (sp)); - return (sp > stacks_end) ? 0 : ((sp - stacks_start) / stack_size + 1); + return (usrstack - sp) / stack_size; } diff --git a/src/os/unix/ngx_init.c b/src/os/unix/ngx_init.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_init.c @@ -0,0 +1,20 @@ + + +int ngx_unix_init(ngx_log_t *log) +{ + struct rlimit rlmt; + + if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, errno, + "getrlimit(RLIMIT_NOFILE) failed)"); + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "getrlimit(RLIMIT_NOFILE): %d", rlmt.rlim_cur); + + RLIM_INFINITY + max_connections =< rlmt.rlim_cur; + + return NGX_OK; +}