# HG changeset patch # User Igor Sysoev # Date 1054213329 0 # Node ID 70d2345a903f09081ef37e3382b89d26932c25fc # Parent a23d010f356df378b3d5c43c9bec759f01b19fee nginx-0.0.1-2003-05-29-17:02:09 import diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -90,8 +90,8 @@ int main(int argc, char *const *argv) conf.module_type = NGX_CORE_MODULE; conf.cmd_type = NGX_MAIN_CONF; - conf_file.len = sizeof("nginx.conf") - 1; - conf_file.data = "nginx.conf"; + conf_file.len = sizeof(NGINX_CONF) - 1; + conf_file.data = NGINX_CONF; if (ngx_conf_parse(&conf, &conf_file) != NGX_CONF_OK) { return 1; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -2,7 +2,8 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.0.1" +#define NGINX_VER "nginx/0.0.1" +#define NGINX_CONF "nginx.conf" extern int ngx_max_module; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -52,9 +52,11 @@ char *ngx_cpystrn(char *dst, char *src, int ngx_rstrncmp(char *s1, char *s2, size_t n); int ngx_atoi(char *line, size_t n); +#define ngx_qsort qsort -#define ngx_value_helper(n) #n -#define ngx_value(n) ngx_value_helper(n) + +#define ngx_value_helper(n) #n +#define ngx_value(n) ngx_value_helper(n) #endif /* _NGX_STRING_H_INCLUDED_ */ 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 @@ -9,7 +9,7 @@ #define DEF_CONNECTIONS 1024 -extern ngx_event_module_t ngx_select_module_ctx; +extern ngx_module_t ngx_select_module; #if (HAVE_KQUEUE) #include @@ -122,12 +122,11 @@ 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_connection_t *c; - ngx_event_conf_t *ecf; + int m, i, fd; + ngx_listen_t *s; + ngx_event_t *ev; + ngx_connection_t *c; + ngx_event_conf_t *ecf; ngx_event_module_t *module; ecf = ngx_event_get_conf(ngx_event_module); 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 @@ -90,9 +90,7 @@ struct ngx_event_s { unsigned ignore_econnreset:1; unsigned unexpected_eof:1; -#if (HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; -#endif #if (HAVE_KQUEUE) unsigned eof:1; @@ -277,6 +275,7 @@ typedef struct { #define ngx_process_events ngx_event_actions.process #define ngx_add_event ngx_event_actions.add #define ngx_del_event ngx_event_actions.del +#define ngx_add_conn ngx_event_actions.add_conn #define ngx_del_conn ngx_event_actions.del_conn #if 0 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 @@ -1,11 +1,9 @@ + +#include +#include #include -#include -#include -#include -#include -#include #include @@ -19,18 +17,17 @@ void ngx_event_accept(ngx_event_t *ev) ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c, *ls; + ngx_event_conf_t *ecf; - ls = (ngx_connection_t *) ev->data; + ecf = ngx_event_get_conf(ngx_event_module); + + ls = ev->data; ngx_log_debug(ev->log, "ngx_event_accept: accept ready: %d" _ ev->available); ev->ready = 0; -#if 0 -/* DEBUG */ ev->available++; -#endif - do { /* Create the pool before accept() to avoid copy the sockaddr. @@ -52,16 +49,37 @@ void ngx_event_accept(ngx_event_t *ev) s = accept(ls->fd, sa, &len); if (s == -1) { err = ngx_socket_errno; - ngx_destroy_pool(pool); 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->addr_text.data); return; } ngx_log_error(NGX_LOG_ALERT, ev->log, err, - "accept %s failed", ls->addr_text.data); + "accept() %s failed", ls->addr_text.data); + + ngx_destroy_pool(pool); + return; + } + + if (s >= ecf->connections) { + + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "accept() %s returned socket #%d while " + "only %d connections was configured, " + "sleeping for 1 second", + ls->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); + } + + sleep(1); + + ngx_destroy_pool(pool); return; } @@ -73,6 +91,14 @@ void ngx_event_accept(ngx_event_t *ev) ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " %s failed", ls->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); + } + + ngx_destroy_pool(pool); return; } } @@ -83,6 +109,14 @@ void ngx_event_accept(ngx_event_t *ev) ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " %s failed", ls->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); + } + + ngx_destroy_pool(pool); return; } } @@ -133,28 +167,28 @@ void ngx_event_accept(ngx_event_t *ev) ngx_memcpy(c->log, ev->log, sizeof(ngx_log_t)); rev->log = wev->log = c->log; - /* STUB: x86: SP: xadd ?, MT: lock xadd, MP: lock xadd, shared */ + /* STUB: x86: MT: lock xadd, MP: lock xadd, shared */ c->number = ngx_connection_counter++; - ngx_log_debug(ev->log, "ngx_event_accept: accept: %d, %d" _ - s _ c->number); + ngx_log_debug(ev->log, "accept: %d, %d" _ s _ c->number); -#if (HAVE_DEFERRED_ACCEPT) - if (ev->accept_filter) { + if (ev->deferred_accept) { rev->ready = 1; } -#endif -#if (HAVE_EDGE_EVENT) /* epoll */ + if (ngx_add_conn) { + if (ngx_add_conn(c) == NGX_ERROR) { + 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); + } - if (ngx_event_flags & NGX_HAVE_EDGE_EVENT) { - if (ngx_edge_add_event(ev) == NGX_ERROR) { + ngx_destroy_pool(pool); return; } } -#endif - ls->handler(c); if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { 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 @@ -59,7 +59,7 @@ int ngx_http_index_handler(ngx_http_requ { int i, rc, test_dir; char *name, *file; - ngx_str_t loc, *index; + ngx_str_t redirect, *index; ngx_err_t err; ngx_fd_t fd; ngx_http_index_conf_t *icf; @@ -74,14 +74,14 @@ int ngx_http_index_handler(ngx_http_requ + icf->max_index_len), NGX_HTTP_INTERNAL_SERVER_ERROR); - loc.data = ngx_cpystrn(r->path.data, clcf->doc_root.data, - clcf->doc_root.len + 1); - file = ngx_cpystrn(loc.data, r->uri.data, r->uri.len + 1); + redirect.data = ngx_cpymem(r->path.data, clcf->doc_root.data, + clcf->doc_root.len); + file = ngx_cpystrn(redirect.data, r->uri.data, r->uri.len + 1); r->path.len = file - r->path.data; test_dir = 1; - index = (ngx_str_t *) icf->indices.elts; + index = icf->indices.elts; for (i = 0; i < icf->indices.nelts; i++) { if (index[i].data[0] != '/') { @@ -136,18 +136,15 @@ ngx_log_error(NGX_LOG_DEBUG, r->connecti if (index[i].data[0] == '/') { r->file.name.len = index[i].len; - loc.len = index[i].len; - loc.data = index[i].data; + redirect.len = index[i].len; + redirect.data = index[i].data; } else { - loc.len = r->uri.len + index[i].len; - r->file.name.len = clcf->doc_root.len + r->uri.len - + index[i].len; + redirect.len = r->uri.len + index[i].len; + r->file.name.len = clcf->doc_root.len + r->uri.len + index[i].len; } -/* STUB */ r->exten.len = 4; r->exten.data = "html"; - - return ngx_http_internal_redirect(r, loc); + return ngx_http_internal_redirect(r, &redirect, NULL); } return NGX_DECLINED; @@ -177,7 +174,6 @@ ngx_log_debug(r->connection->log, "IS_DI } ngx_log_error(NGX_LOG_CRIT, r->connection->log, r->path_err, - "ngx_http_index_test_dir: " ngx_file_type_n " %s failed", r->path.data); return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -263,7 +259,7 @@ static char *ngx_http_index_merge_conf(n } -/* TODO: check duplicate indices */ +/* TODO: warn about duplicate indices */ static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) @@ -283,7 +279,9 @@ static char *ngx_http_index_set_index(ng for (i = 1; i < cf->args->nelts; i++) { if (value[i].len == 0) { - return "is invalid"; + ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1, + "index \"%s\" is invalid", value[1].data); + return ngx_conf_errstr; } ngx_test_null(index, ngx_push_array(&icf->indices), NGX_CONF_ERROR); @@ -295,5 +293,5 @@ static char *ngx_http_index_set_index(ng } } - return NULL; + return NGX_CONF_OK; } diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_cache.c @@ -0,0 +1,63 @@ + + + +#define NGX_HTTP_CACHE_ENTRY_DELETED 0x00000001 +#define NGX_HTTP_CACHE_ENTRY_MMAPED 0x00000002 + +/* "/" -> "/index.html" in ngx_http_index_handler */ +#define NGX_HTTP_CACHE_ENTRY_URI 0x00000004 + +#define NGX_HTTP_CACHE_FILTER_FLAGS 0xFFFF0000 + + +typedef struct { + ngx_fd_t fd; + off_t size; + void *data; + time_t accessed; + time_t last_modified; + time_t updated; /* no needed with kqueue */ + int refs; + int flags; +} ngx_http_cache_entry_t; + + +typedef struct { + u_int32_t crc; + ngx_str_t uri; + ngx_http_cache_t *cache; +} ngx_http_cache_hash_entry_t; + + +typedef struct { + ngx_http_cache_t *cache; + u_int32_t crc; + int n; +} ngx_http_cache_handle_t; + + +int ngx_http_cache_get(ngx_http_cache_hash_t *cache_hash, + ngx_str_t *uri, ngx_http_cache_handle_t *h) +{ + int hi; + ngx_http_cache_hash_entry_t *entry; + + h->crc = ngx_crc32(uri->data, uri->len); + + hi = h->crc % cache_hash->size; + entry = cache_hash[hi].elts; + + for (i = 0; i < cache_hash[hi].nelts; i++) { + if (entry[i].crc == crc + && entry[i].uri.len == uri->len + && ngx_strncmp(entry[i].uri.data, uri->data, uri->len) == 0 + { + h->cache = entry[i].cache; + h->cache->refs++; + h->n = hi; + return NGX_OK; + } + } + + return NGX_ERROR; +} 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 @@ -28,10 +28,13 @@ static char *ngx_http_core_merge_loc_con static int ngx_http_core_init(ngx_pool_t *pool); static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); +static int ngx_cmp_locations(const void *first, const void *second); static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); static char *ngx_types_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_http_core_commands[] = { @@ -41,7 +44,7 @@ static ngx_command_t ngx_http_core_comm ngx_server_block, 0, 0, - NULL,}, + NULL}, {ngx_string("connection_pool_size"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -99,6 +102,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL}, + {ngx_string("server_name"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_ANY, + ngx_set_server_name, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL}, + {ngx_string("types"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF |NGX_CONF_BLOCK|NGX_CONF_NOARGS, @@ -215,8 +225,10 @@ ngx_log_debug(r->connection->log, "trans continue; } - rc = ngx_rstrncmp(r->uri.data, clcfp[i]->name.data, - clcfp[i]->name.len); + rc = ngx_strncmp(r->uri.data, clcfp[i]->name.data, + clcfp[i]->name.len); + +ngx_log_debug(r->connection->log, "rc: %d" _ rc); if (rc < 0) { break; @@ -235,9 +247,10 @@ ngx_log_debug(r->connection->log, "trans /* run translation phase */ - h = (ngx_http_handler_pt *) ngx_http_translate_handlers.elts; - for (i = ngx_http_translate_handlers.nelts; i > 0; /* void */) { - rc = h[--i](r); + h = ngx_http_translate_handlers.elts; + for (i = ngx_http_translate_handlers.nelts - 1; i >= 0; i--) { + + rc = h[i](r); if (rc == NGX_DECLINED) { continue; @@ -457,21 +470,46 @@ int ngx_http_error(ngx_http_request_t *r } -int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri) +int ngx_http_internal_redirect(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args) { - ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri.data); + int i; + + ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri->data); + + r->uri.len = uri->len; + r->uri.data = uri->data; + + if (args) { + r->args.len = args->len; + r->args.data = args->data; + } + + r->exten.len = 0; + r->exten.data = NULL; - r->uri.len = uri.len; - r->uri.data = uri.data; + for (i = uri->len - 1; i > 1; i--) { + if (uri->data[i] == '.' && uri->data[i - 1] != '/') { + r->exten.len = uri->len - i - 1; + + if (r->exten.len > 0) { + ngx_test_null(r->exten.data, + ngx_palloc(r->pool, r->exten.len + 1), + NGX_HTTP_INTERNAL_SERVER_ERROR); - /* BROKEN, NEEDED ? */ - /* r->exten */ - r->uri_start = uri.data; - r->uri_end = uri.data + uri.len; - /**/ + ngx_cpystrn(r->exten.data, &uri->data[i + 1], r->exten.len + 1); + } + + break; + + } else if (uri->data[i] == '/') { + break; + } + } ngx_http_handler(r); - return 0; + + return NGX_OK; } @@ -554,10 +592,26 @@ static char *ngx_server_block(ngx_conf_t rv = ngx_conf_parse(cf, NULL); *cf = pcf; + if (rv != NGX_CONF_OK) { + return rv; + } + + ngx_qsort(cscf->locations.elts, cscf->locations.nelts, + sizeof(void *), ngx_cmp_locations); + return rv; } +static int ngx_cmp_locations(const void *first, const void *second) +{ + ngx_http_core_loc_conf_t *one = *(ngx_http_core_loc_conf_t **) first; + ngx_http_core_loc_conf_t *two = *(ngx_http_core_loc_conf_t **) second; + + return ngx_strcmp(one->name.data, two->name.data); +} + + static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { int m; @@ -724,6 +778,7 @@ static char *ngx_http_core_merge_srv_con ngx_http_core_srv_conf_t *prev = (ngx_http_core_srv_conf_t *) parent; ngx_http_core_srv_conf_t *conf = (ngx_http_core_srv_conf_t *) child; + ngx_err_t err; ngx_http_listen_t *l; ngx_http_server_name_t *n; @@ -740,10 +795,15 @@ static char *ngx_http_core_merge_srv_con ngx_test_null(n, ngx_push_array(&conf->server_names), NGX_CONF_ERROR); ngx_test_null(n->name.data, ngx_palloc(pool, NGX_MAXHOSTNAMELEN), NGX_CONF_ERROR); + if (gethostname(n->name.data, NGX_MAXHOSTNAMELEN) == -1) { - /* TODO: need ngx_errno here */ - return "gethostname() failed"; + err = ngx_errno; + ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1, + "gethostname() failed (%d: %s)", + err, ngx_strerror(err)); + return ngx_conf_errstr; } + n->name.len = ngx_strlen(n->name.data); n->core_srv_conf = conf; } @@ -868,7 +928,7 @@ static char *ngx_set_listen(ngx_conf_t * ngx_http_listen_t *ls; /* TODO: check duplicate 'listen' directives, - add resolved name to server names */ + add resolved name to server names ??? */ ngx_test_null(ls, ngx_push_array(&scf->listen), NGX_CONF_ERROR); @@ -879,37 +939,75 @@ static char *ngx_set_listen(ngx_conf_t * ls->file_name = cf->conf_file->file.name; ls->line = cf->conf_file->line; - args = (ngx_str_t *) cf->args->elts; + args = cf->args->elts; addr = args[1].data; for (p = 0; p < args[1].len; p++) { if (addr[p] == ':') { addr[p++] = '\0'; - - ls->addr = inet_addr(addr); - if (ls->addr == INADDR_NONE) { - h = gethostbyname(addr); - - if (h == NULL || h->h_addr_list[0] == NULL) { - return "can not resolve host name"; - } - - ls->addr = *(u_int32_t *)(h->h_addr_list[0]); - } - break; } } if (p == args[1].len) { - ls->addr = INADDR_ANY; + /* no ":" in the "listen" */ p = 0; } ls->port = ngx_atoi(&addr[p], args[1].len - p); - if (ls->port < 1 || ls->port > 65536) { - return "port must be between 1 and 65535"; + if (ls->port == NGX_ERROR && p == 0) { + + /* "listen host" */ + ls->port = 80; + + } else if ((ls->port == NGX_ERROR && p != 0) /* "listen host:NONNUMBER" */ + || (ls->port < 1 || ls->port > 65536)) { /* "listen 99999" */ + + ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1, + "invalid port \"%s\", " + "it must be a number between 1 and 65535", + &addr[p]); + return ngx_conf_errstr; + + } else if (p == 0) { + ls->addr = INADDR_ANY; + return NGX_CONF_OK; + } + + ls->addr = inet_addr(addr); + if (ls->addr == INADDR_NONE) { + h = gethostbyname(addr); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1, + "can not resolve host \"%s\"", addr); + return ngx_conf_errstr; + } + + ls->addr = *(u_int32_t *)(h->h_addr_list[0]); } return NGX_CONF_OK; } + + +static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_srv_conf_t *scf = (ngx_http_core_srv_conf_t *) conf; + + ngx_str_t *args; + ngx_http_server_name_t *sn; + + /* TODO: several names */ + /* TODO: warn about duplicate 'server_name' directives */ + + ngx_test_null(sn, ngx_push_array(&scf->server_names), NGX_CONF_ERROR); + + args = cf->args->elts; + + sn->name.len = args[1].len; + sn->name.data = args[1].data; + sn->core_srv_conf = scf; + + return NGX_CONF_OK; +} 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 @@ -138,7 +138,8 @@ extern int ngx_http_max_module; int ngx_http_core_translate_handler(ngx_http_request_t *r); -int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri); +int ngx_http_internal_redirect(ngx_http_request_t *r, + ngx_str_t *uri, ngx_str_t *args); int ngx_http_error(ngx_http_request_t *r, int error); diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -24,6 +24,8 @@ typedef int ngx_err_t; #define ngx_socket_errno errno #define ngx_set_socket_errno(err) errno = err +#define ngx_strerror(err) strerror(err) + #define ngx_strerror_r(err, errstr, size) \ ngx_cpystrn(errstr, strerror(err), size) - (errstr) diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -2,6 +2,7 @@ #include +/* FreeBSD 3.4 at least */ char ngx_freebsd_kern_ostype[20]; char ngx_freebsd_kern_osrelease[20]; int ngx_freebsd_kern_osreldate; @@ -9,6 +10,9 @@ int ngx_freebsd_hw_ncpu; int ngx_freebsd_net_inet_tcp_sendspace; int ngx_freebsd_sendfile_nbytes_bug; +/* FreeBSD 5.0 */ +int ngx_freebsd_kern_ipc_zero_copy_send; + ngx_os_io_t ngx_os_io = { ngx_unix_recv, @@ -19,9 +23,35 @@ ngx_os_io_t ngx_os_io = { }; +typedef struct { + char *name; + int *value; + size_t size; +} sysctl_t; + + +sysctl_t sysctls[] = { + {"hw.ncpu", + &ngx_freebsd_hw_ncpu, + sizeof(int)}, + + {"net.inet.tcp.sendspace", + &ngx_freebsd_net_inet_tcp_sendspace, + sizeof(int)}, + + {"kern.ipc.zero_copy.send", + &ngx_freebsd_kern_ipc_zero_copy_send, + sizeof(int)}, + + {NULL, NULL, 0} +}; + + int ngx_os_init(ngx_log_t *log) { - size_t size; + int i; + size_t size; + ngx_err_t err; size = 20; if (sysctlbyname("kern.ostype", @@ -85,28 +115,23 @@ int ngx_os_init(ngx_log_t *log) #endif /* HAVE_FREEBSD_SENDFILE */ - size = 4; - if (sysctlbyname("hw.ncpu", &ngx_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", ngx_freebsd_hw_ncpu); - + for (i = 0; sysctls[i].name; i++) { + *sysctls[i].value = 0; + size = sysctls[i].size; + if (sysctlbyname(sysctls[i].name, sysctls[i].value, &size, NULL, 0) + == -1) { + err = errno; + if (err != NGX_ENOENT) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "sysctlbyname(%s) failed", sysctls[i].name); + return NGX_ERROR; + } - size = 4; - if (sysctlbyname("net.inet.tcp.sendspace", - &ngx_freebsd_net_inet_tcp_sendspace, - &size, NULL, 0) == -1) - { - ngx_log_error(NGX_LOG_ALERT, log, errno, - "sysctlbyname(net.inet.tcp.sendspace) failed"); - return NGX_ERROR; + } else { + ngx_log_error(NGX_LOG_INFO, log, 0, "%s: %d", + sysctls[i].name, *sysctls[i].value); + } } - ngx_log_error(NGX_LOG_INFO, log, 0, "net.inet.tcp.sendspace: %d", - ngx_freebsd_net_inet_tcp_sendspace); - return ngx_posix_init(log); } 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 @@ -26,6 +26,7 @@ #include #include #include +#include typedef unsigned int u_int; diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -0,0 +1,183 @@ + +#include +#include +#include + + +ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) +{ + int rc, on, off; + char *prev; + size_t hsize, size; + ssize_t sent; + struct iovec *iov; + struct sf_hdtr hdtr; + ngx_err_t err; + ngx_array_t header, trailer; + ngx_hunk_t *file; + ngx_chain_t *ce; + + ce = in; + file = NULL; + hsize = 0; + + on = 1; + off = 0; + + ngx_init_array(header, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); + ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); + + /* create the header iovec */ + if (ngx_hunk_in_memory_only(ce->hunk)) { + prev = NULL; + iov = NULL; + + /* create the iovec and coalesce the neighbouring chain entries */ + while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + if (prev == ce->hunk->pos) { + iov->iov_len += ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + + } else { + ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); + iov->iov_base = ce->hunk->pos; + iov->iov_len = ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + } + + if (ngx_freebsd_sendfile_nbytes_bug) { + hsize += ce->hunk->last - ce->hunk->pos; + } + + ce = ce->next; + } + } + + /* TODO: coalesce the neighbouring file hunks */ + if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { + file = ce->hunk; + ce = ce->next; + } + + /* create the trailer iovec */ + if (ce && ngx_hunk_in_memory_only(ce->hunk)) { + prev = NULL; + iov = NULL; + + /* create the iovec and coalesce the neighbouring chain entries */ + while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + if (prev == ce->hunk->pos) { + iov->iov_len += ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + + } else { + ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR); + iov->iov_base = ce->hunk->pos; + iov->iov_len = ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; + } + + ce = ce->next; + } + } + + if (file) { + if (setsockopt(c->fd, IPPROTO_TCP, TCP_CORK, + (const void *) &on, sizeof(int)) == -1) { + ngx_log_error(NGX_LOG_CRIT, c->log, err, + "setsockopt(TCP_CORK, 1) failed"); + return NGX_CHAIN_ERROR; + } + + + rc = sendfile(c->fd, file->file->fd, file->file_pos, + (size_t) (file->file_last - file->file_pos)); + + if (rc == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EAGAIN"); + + } else if (err == NGX_EINTR) { + ngx_log_error(NGX_LOG_INFO, c->log, err, "senfile() EINTR"); + + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, "sendfile() failed"); + return NGX_CHAIN_ERROR; + } + } + + sent = rc > 0 ? rc : 0; + +#if (NGX_DEBUG_WRITE_CHAIN) + ngx_log_debug(c->log, "sendfile: %d, @%qd %d:%d" _ + rc _ file->file_pos _ sent _ + (size_t) (file->file_last - file->file_pos)); +#endif + + } else { + rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); + + if (rc == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); + + } else if (err == NGX_EINTR) { + ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); + + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); + return NGX_CHAIN_ERROR; + } + } + + sent = rc > 0 ? rc : 0; + +#if (NGX_DEBUG_WRITE_CHAIN) + ngx_log_debug(c->log, "writev: %d" _ sent); +#endif + } + + c->sent += sent; + + for (ce = in; ce && sent > 0; ce = ce->next) { + + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + size = ce->hunk->last - ce->hunk->pos; + } else { + size = ce->hunk->file_last - ce->hunk->file_pos; + } + + if (sent >= size) { + sent -= size; + + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos = ce->hunk->last; + } + + if (ce->hunk->type & NGX_HUNK_FILE) { + ce->hunk->file_pos = ce->hunk->file_last; + } + + continue; + } + + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos += sent; + } + + if (ce->hunk->type & NGX_HUNK_FILE) { + ce->hunk->file_pos += sent; + } + + break; + } + + ngx_destroy_array(&trailer); + ngx_destroy_array(&header); + + return ce; +} 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 @@ -22,6 +22,7 @@ #include #include #include +#include typedef uint32_t u_int32_t;