# HG changeset patch # User Igor Sysoev # Date 1127419200 -14400 # Node ID 45945fa8b8badb98be1556c7e6b33d6044f69d8f # Parent c3eee83ea942ada385626c2414eee0b2d5cfb0fe nginx 0.2.0 *) The pid-file names used during online upgrade was changed and now is not required a manual rename operation. The old master process adds the ".oldbin" suffix to its pid-file and executes a new binary file. The new master process creates usual pid-file without the ".newbin" suffix. If the master process exits, then old master process renames back its pid-file with the ".oldbin" suffix to the pid-file without suffix. *) Change: the "worker_connections" directive, new name of the "connections" directive; now the directive specifies maximum number of connections, but not maximum socket descriptor number. *) Feature: SSL supports the session cache inside one worker process. *) Feature: the "satisfy_any" directive. *) Change: the ngx_http_access_module and ngx_http_auth_basic_module do not run for subrequests. *) Feature: the "worker_rlimit_nofile" and "worker_rlimit_sigpending" directives. *) Bugfix: if all backend using in load-balancing failed after one error, then nginx did not try do connect to them during 60 seconds. *) Bugfix: in IMAP/POP3 command argument parsing. Thanks to Rob Mueller. *) Bugfix: errors while using SSL in IMAP/POP3 proxy. *) Bugfix: errors while using SSI and gzipping. *) Bugfix: the "Expires" and "Cache-Control" header lines were omitted from the 304 responses. Thanks to Alexandr Kukushkin. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,40 @@ + +Changes with nginx 0.2.0 23 Sep 2005 + + *) The pid-file names used during online upgrade was changed and now is + not required a manual rename operation. The old master process adds + the ".oldbin" suffix to its pid-file and executes a new binary file. + The new master process creates usual pid-file without the ".newbin" + suffix. If the master process exits, then old master process renames + back its pid-file with the ".oldbin" suffix to the pid-file without + suffix. + + *) Change: the "worker_connections" directive, new name of the + "connections" directive; now the directive specifies maximum number + of connections, but not maximum socket descriptor number. + + *) Feature: SSL supports the session cache inside one worker process. + + *) Feature: the "satisfy_any" directive. + + *) Change: the ngx_http_access_module and ngx_http_auth_basic_module do + not run for subrequests. + + *) Feature: the "worker_rlimit_nofile" and "worker_rlimit_sigpending" + directives. + + *) Bugfix: if all backend using in load-balancing failed after one + error, then nginx did not try do connect to them during 60 seconds. + + *) Bugfix: in IMAP/POP3 command argument parsing. Thanks to Rob Mueller. + + *) Bugfix: errors while using SSL in IMAP/POP3 proxy. + + *) Bugfix: errors while using SSI and gzipping. + + *) Bugfix: the "Expires" and "Cache-Control" header lines were omitted + from the 304 responses. Thanks to Alexandr Kukushkin. + Changes with nginx 0.1.45 08 Sep 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,45 @@ + +Изменения в nginx 0.2.0 23.09.2005 + + *) Изменились имена pid-файлов, используемые во время обновления + исполняемого файла. Ручное переименование теперь не нужно. Старый + основной процесс добавляет к своему pid-файл суффикс ".oldbin" и + запускает новый исполняемый файл. Новый основной процесс создаёт + обычный pid-файл без суффикса ".newbin". Если новый основной процесс + выходит, то старый процесс переименовывает свой pid-файл c суффиксом + ".oldbin" в pid-файл без суффикса. При обновлении с версии 0.1.х до + 0.2.0 нужно учитывать, что старый процесс 0.1.x и новый процесс + 0.2.0 оба используют pid-файл без суффиксов. + + *) Изменение: директива worker_connections, новое название директивы + connections; директива теперь задаёт максимальное число соединений, + а не максимально возможный номер дескриптора для сокета. + + *) Добавление: SSL поддерживает кэширование сессий в пределах одного + рабочего процесса. + + *) Добавление: директива satisfy_any. + + *) Изменение: модули ngx_http_access_module и + ngx_http_auth_basic_module не работают для подзапросов. + + *) Добавление: директивы worker_rlimit_nofile и + worker_rlimit_sigpending. + + *) Исправление: если все бэкенды, используемые для балансировки + нагрузки, оказывались в нерабочем состоянии после одной ошибки, то + nginx не обращался к ним в течение 60 секунд. + + *) Исправление: в парсинге аргументов IMAP/POP3 команд. Спасибо Rob + Mueller. + + *) Исправление: ошибки при использовании SSL в IMAP/POP3 прокси. + + *) Исправление: ошибки при использовании SSI и сжатия. + + *) Исправление: в ответах 304 не добавлялись строки заголовка ответа + "Expires" и "Cache-Control". Спасибо Александру Кукушкину. + Изменения в nginx 0.1.45 08.09.2005 diff --git a/auto/init b/auto/init --- a/auto/init +++ b/auto/init @@ -54,8 +54,16 @@ clean: upgrade: $NGX_SBIN_PATH -t + + # upgrade compatibility from 0.1.x to 0.2.x + cp $NGX_PID_PATH $NGX_PID_PATH.oldbin + kill -USR2 \`cat $NGX_PID_PATH\` sleep 1 - test -f $NGX_PID_PATH.newbin - kill -WINCH \`cat $NGX_PID_PATH\` + test -f $NGX_PID_PATH.oldbin + + # upgrade compatibility from 0.1.x to 0.2.x + cp $NGX_PID_PATH $NGX_PID_PATH.newbin + + kill -WINCH \`cat $NGX_PID_PATH.oldbin\` END diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -2,6 +2,21 @@ # Copyright (C) Igor Sysoev +### STUB + +if [ $USE_THREADS != NO ]; then + +cat << END + +$0: error: the threads support is broken now. + +END + exit 1 + fi + +### + + echo echo "Configuration summary" diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -42,6 +42,13 @@ static ngx_command_t ngx_core_commands[ offsetof(ngx_core_conf_t, master), NULL }, + { ngx_string("pid"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_core_conf_t, pid), + NULL }, + { ngx_string("worker_processes"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -56,6 +63,41 @@ static ngx_command_t ngx_core_commands[ offsetof(ngx_core_conf_t, debug_points), &ngx_debug_points }, + { ngx_string("user"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12, + ngx_set_user, + 0, + 0, + NULL }, + + { ngx_string("worker_priority"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_set_priority, + 0, + 0, + NULL }, + + { ngx_string("worker_rlimit_nofile"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_core_conf_t, rlimit_nofile), + NULL }, + + { ngx_string("worker_rlimit_sigpending"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + 0, + offsetof(ngx_core_conf_t, rlimit_sigpending), + NULL }, + + { ngx_string("working_directory"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_core_conf_t, working_directory), + NULL }, + #if (NGX_THREADS) { ngx_string("worker_threads"), @@ -74,34 +116,6 @@ static ngx_command_t ngx_core_commands[ #endif - { ngx_string("user"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12, - ngx_set_user, - 0, - 0, - NULL }, - - { ngx_string("worker_priority"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_set_priority, - 0, - 0, - NULL }, - - { ngx_string("pid"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - 0, - offsetof(ngx_core_conf_t, pid), - NULL }, - - { ngx_string("working_directory"), - NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - 0, - offsetof(ngx_core_conf_t, working_directory), - NULL }, - ngx_null_command }; @@ -324,13 +338,15 @@ ngx_add_inherited_sockets(ngx_cycle_t *c } -ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) +ngx_pid_t +ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { char *env[3], *var; u_char *p; ngx_uint_t i; ngx_pid_t pid; ngx_exec_ctx_t ctx; + ngx_core_conf_t *ccf; ngx_listening_t *ls; ctx.path = argv[0]; @@ -374,15 +390,42 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_ ctx.envp = (char *const *) &env; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ngx_rename_file((char *) ccf->pid.data, (char *) ccf->oldpid.data) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_rename_file_n " %s to %s failed " + "before executing new binary process \"%s\"", + ccf->pid.data, ccf->oldpid.data, argv[0]); + + ngx_free(var); + + return NGX_INVALID_PID; + } + pid = ngx_execute(cycle, &ctx); + if (pid == NGX_INVALID_PID) { + if (ngx_rename_file((char *) ccf->oldpid.data, (char *) ccf->pid.data) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_rename_file_n " %s back to %s failed " + "after try to executing new binary process \"%s\"", + ccf->oldpid.data, ccf->pid.data, argv[0]); + } + } + ngx_free(var); return pid; } -static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv) +static ngx_int_t +ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv) { ngx_int_t i; @@ -485,7 +528,7 @@ ngx_core_module_create_conf(ngx_cycle_t * set by pcalloc() * * ccf->pid = NULL; - * ccf->newpid = NULL; + * ccf->oldpid = NULL; * ccf->priority = 0; */ @@ -493,8 +536,13 @@ ngx_core_module_create_conf(ngx_cycle_t ccf->master = NGX_CONF_UNSET; ccf->worker_processes = NGX_CONF_UNSET; ccf->debug_points = NGX_CONF_UNSET; + + ccf->rlimit_nofile = NGX_CONF_UNSET; + ccf->rlimit_sigpending = NGX_CONF_UNSET; + ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT; ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT; + #if (NGX_THREADS) ccf->worker_threads = NGX_CONF_UNSET; ccf->thread_stack_size = NGX_CONF_UNSET_SIZE; @@ -558,15 +606,15 @@ ngx_core_module_init_conf(ngx_cycle_t *c return NGX_CONF_ERROR; } - ccf->newpid.len = ccf->pid.len + sizeof(NGX_NEWPID_EXT); + ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); - ccf->newpid.data = ngx_palloc(cycle->pool, ccf->newpid.len); - if (ccf->newpid.data == NULL) { + ccf->oldpid.data = ngx_palloc(cycle->pool, ccf->oldpid.len); + if (ccf->oldpid.data == NULL) { return NGX_CONF_ERROR; } - ngx_memcpy(ngx_cpymem(ccf->newpid.data, ccf->pid.data, ccf->pid.len), - NGX_NEWPID_EXT, sizeof(NGX_NEWPID_EXT)); + ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), + NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); #endif diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,10 +8,10 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.1.45" +#define NGINX_VER "nginx/0.2.0" #define NGINX_VAR "NGINX" -#define NGX_NEWPID_EXT ".newbin" +#define NGX_OLDPID_EXT ".oldbin" #endif /* _NGINX_H_INCLUDED_ */ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -62,6 +62,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t char *rv; ngx_fd_t fd; ngx_int_t rc; + ngx_uint_t block; ngx_conf_file_t *prev; #if (NGX_SUPPRESS_WARN) @@ -103,13 +104,20 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log;; cf->conf_file->line = 1; + + block = 0; + + } else { + block = 1; } + for ( ;; ) { rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return + * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found @@ -121,6 +129,19 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t break; } + if (rc == NGX_CONF_BLOCK_DONE) { + block = 0; + } + + if (rc == NGX_CONF_FILE_DONE && block) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unexpected end of file in %s:%ui, expecting \"}\"", + cf->conf_file->file.name.data, + cf->conf_file->line); + rc = NGX_ERROR; + break; + } + if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) { break; } @@ -639,7 +660,7 @@ ngx_conf_full_name(ngx_cycle_t *cycle, n name->len = cycle->root.len + old.len; - if (cycle->connections) { + if (cycle->connections0) { name->data = ngx_palloc(cycle->pool, name->len + 1); if (name->data == NULL) { return NGX_ERROR; diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -237,13 +237,14 @@ ngx_open_listening_sockets(ngx_cycle_t * } #if (NGX_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_log_error(NGX_LOG_EMERG, log, 0, ngx_socket_n " created socket %d", s); return NGX_ERROR; } @@ -329,9 +330,9 @@ ngx_open_listening_sockets(ngx_cycle_t * void ngx_close_listening_sockets(ngx_cycle_t *cycle) { - ngx_uint_t i; - ngx_socket_t fd; - ngx_listening_t *ls; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_connection_t *c; if (ngx_event_flags & NGX_USE_IOCP_EVENT) { return; @@ -342,35 +343,87 @@ ngx_close_listening_sockets(ngx_cycle_t ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - fd = ls[i].fd; -#if (NGX_WIN32) - /* - * Winsock assignes a socket number divisible by 4 - * so to find a connection we divide a socket number by 4. - */ - - fd /= 4; -#endif + c = ls[i].connection; if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (cycle->connections[fd].read->active) { - ngx_del_conn(&cycle->connections[fd], NGX_CLOSE_EVENT); + if (c->read->active) { + ngx_del_conn(c, NGX_CLOSE_EVENT); } } else { - if (cycle->read_events[fd].active) { - ngx_del_event(&cycle->read_events[fd], - NGX_READ_EVENT, NGX_CLOSE_EVENT); + if (c->read->active) { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); } } - if (ngx_close_socket(fd) == -1) { + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; + + if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } + } +} - cycle->connections[fd].fd = (ngx_socket_t) -1; + +ngx_connection_t * +ngx_get_connection(ngx_socket_t s, ngx_log_t *log) +{ + ngx_connection_t *c; + + /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */ + + if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "the new socket has number %d, " + "but only %ui files are available", + s, ngx_cycle->files_n); + return NULL; + } + + /* ngx_mutex_lock */ + + c = ngx_cycle->free_connections; + + if (c == NULL) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "%ui worker_connections is not enough", + ngx_cycle->connection_n); + + /* ngx_mutex_unlock */ + + return NULL; + } + + ngx_cycle->free_connections = c->data; + ngx_cycle->free_connection_n--; + + /* ngx_mutex_unlock */ + + if (ngx_cycle->files) { + ngx_cycle->files[s] = c; + } + + return c; +} + + +void +ngx_free_connection(ngx_connection_t *c) +{ + /* ngx_mutex_lock */ + + c->data = ngx_cycle->free_connections; + ngx_cycle->free_connections = c; + ngx_cycle->free_connection_n++; + + /* ngx_mutex_unlock */ + + if (ngx_cycle->files) { + ngx_cycle->files[c->fd] = NULL; } } @@ -451,9 +504,10 @@ ngx_close_connection(ngx_connection_t *c #endif + ngx_free_connection(c); + fd = c->fd; c->fd = (ngx_socket_t) -1; - c->data = NULL; if (ngx_close_socket(fd) == -1) { 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 @@ -12,54 +12,60 @@ #include -typedef struct { - ngx_socket_t fd; +typedef struct ngx_listening_s ngx_listening_t; + +struct ngx_listening_s { + ngx_socket_t fd; - struct sockaddr *sockaddr; - socklen_t socklen; /* size of sockaddr */ - size_t addr; /* offset to address in sockaddr */ - size_t addr_text_max_len; - ngx_str_t addr_text; + struct sockaddr *sockaddr; + socklen_t socklen; /* size of sockaddr */ + size_t addr; /* offset to address in sockaddr */ + size_t addr_text_max_len; + ngx_str_t addr_text; - int family; - int type; + int family; + int type; + int backlog; - 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 */ + /* handler of accepted connection */ + void (*handler)(ngx_connection_t *c); + + 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; + ngx_log_t log; - size_t pool_size; - size_t 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 */ + size_t pool_size; + /* should be here because of the AcceptEx() preread */ + size_t post_accept_buffer_size; + /* should be here because of the deferred accept */ + time_t post_accept_timeout; + + ngx_listening_t *previous; + ngx_connection_t *connection; - unsigned open:1; - unsigned remain:1; - unsigned ignore:1; + unsigned open:1; + unsigned remain:1; + unsigned ignore:1; - unsigned bound:1; /* already bound */ - unsigned inherited:1; /* inherited from previous process */ - unsigned nonblocking_accept:1; - unsigned change_backlog:1; - unsigned nonblocking:1; - unsigned shared:1; /* shared between threads or processes */ - unsigned addr_ntop:1; + unsigned bound:1; /* already bound */ + unsigned inherited:1; /* inherited from previous process */ + unsigned nonblocking_accept:1; + unsigned change_backlog:1; + unsigned nonblocking:1; + unsigned shared:1; /* shared between threads or processes */ + unsigned addr_ntop:1; #if (NGX_HAVE_DEFERRED_ACCEPT) - unsigned deferred_accept:1; - unsigned delete_deferred:1; - unsigned add_deferred:1; + unsigned deferred_accept:1; + unsigned delete_deferred:1; + unsigned add_deferred:1; #ifdef SO_ACCEPTFILTER - char *accept_filter; + char *accept_filter; #endif #endif -} ngx_listening_t; +}; typedef enum { @@ -160,8 +166,8 @@ void ngx_close_listening_sockets(ngx_cyc void ngx_close_connection(ngx_connection_t *c); ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text); - -extern ngx_os_io_t ngx_io; +ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log); +void ngx_free_connection(ngx_connection_t *c); #endif /* _NGX_CONNECTION_H_INCLUDED_ */ diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -336,7 +336,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } nls[n].fd = ls[i].fd; - nls[n].remain = 1; + nls[n].previous = &ls[i]; ls[i].remain = 1; if (ls[n].backlog != nls[i].backlog) { @@ -594,7 +594,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %V failed", + ngx_close_socket_n " listening socket on %V failed", &ls[i].addr_text); } } @@ -627,7 +627,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } } - if (old_cycle->connections == NULL) { + if (old_cycle->connections0 == NULL) { /* an old cycle is an init cycle */ ngx_destroy_pool(old_cycle->pool); return cycle; @@ -742,7 +742,8 @@ ngx_int_t ngx_create_pidfile(ngx_cycle_t } ngx_memzero(&file, sizeof(ngx_file_t)); - file.name = (ngx_inherited && getppid() > 1) ? ccf->newpid : ccf->pid; + + file.name = ccf->pid; file.log = cycle->log; trunc = ngx_test_config ? 0: NGX_FILE_TRUNCATE; @@ -786,12 +787,7 @@ void ngx_delete_pidfile(ngx_cycle_t *cyc ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); - if (ngx_inherited && getppid() > 1) { - name = ccf->newpid.data; - - } else { - name = ccf->pid.data; - } + name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data; if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, @@ -963,7 +959,7 @@ static void ngx_clean_old_cycles(ngx_eve found = 0; for (n = 0; n < cycle[i]->connection_n; n++) { - if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) { + if (cycle[i]->connections0[n].fd != (ngx_socket_t) -1) { found = 1; ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%d", n); diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -28,14 +28,20 @@ struct ngx_cycle_s { ngx_log_t *log; ngx_log_t *new_log; + ngx_connection_t **files; + ngx_connection_t *free_connections; + ngx_uint_t free_connection_n; + ngx_array_t listening; ngx_array_t pathes; ngx_list_t open_files; ngx_uint_t connection_n; - ngx_connection_t *connections; - ngx_event_t *read_events; - ngx_event_t *write_events; + ngx_uint_t files_n; + + ngx_connection_t *connections0; + ngx_event_t *read_events0; + ngx_event_t *write_events0; ngx_cycle_t *old_cycle; @@ -51,6 +57,9 @@ typedef struct { ngx_int_t worker_processes; ngx_int_t debug_points; + ngx_int_t rlimit_nofile; + ngx_int_t rlimit_sigpending; + int priority; char *username; @@ -60,7 +69,7 @@ typedef struct { ngx_str_t working_directory; ngx_str_t pid; - ngx_str_t newpid; + ngx_str_t oldpid; #if (NGX_THREADS) ngx_int_t worker_threads; diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -72,13 +72,13 @@ struct ngx_log_s { #define NGX_HAVE_VARIADIC_MACROS 1 #define ngx_log_error(level, log, args...) \ - if (log->log_level >= level) ngx_log_error_core(level, log, args) + if ((log)->log_level >= level) ngx_log_error_core(level, log, args) void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...); #define ngx_log_debug(level, log, args...) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_error_core(NGX_LOG_DEBUG, log, args) /*********************************/ @@ -88,13 +88,13 @@ void ngx_log_error_core(ngx_uint_t level #define NGX_HAVE_VARIADIC_MACROS 1 #define ngx_log_error(level, log, ...) \ - if (log->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__) + if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__) void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, const char *fmt, ...); #define ngx_log_debug(level, log, ...) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__) /*********************************/ @@ -134,43 +134,43 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo #else /* NO VARIADIC MACROS */ #define ngx_log_debug0(level, log, err, fmt) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt) #define ngx_log_debug1(level, log, err, fmt, arg1) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1) #define ngx_log_debug2(level, log, err, fmt, arg1, arg2) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1, arg2) #define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3) #define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4) #define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5) #define ngx_log_debug6(level, log, err, fmt, \ arg1, arg2, arg3, arg4, arg5, arg6) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6) #define ngx_log_debug7(level, log, err, fmt, \ arg1, arg2, arg3, arg4, arg5, arg6, arg7) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, \ arg1, arg2, arg3, arg4, arg5, arg6, arg7) #define ngx_log_debug8(level, log, err, fmt, \ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \ - if (log->log_level & level) \ + if ((log)->log_level & level) \ ngx_log_debug_core(log, err, fmt, \ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -177,7 +177,7 @@ ngx_devpoll_init(ngx_cycle_t *cycle) ngx_event_actions = ngx_devpoll_module_ctx.actions; - ngx_event_flags = NGX_USE_LEVEL_EVENT; + ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT; return NGX_OK; } @@ -449,10 +449,10 @@ ngx_devpoll_process_events(ngx_cycle_t * lock = 1; for (i = 0; i < events; i++) { - c = &ngx_cycle->connections[event_list[i].fd]; + c = ngx_cycle->files[event_list[i].fd]; if (c->fd == -1) { - if (ngx_cycle->read_events[event_list[i].fd].closed) { + if (c->read->closed) { continue; } @@ -460,26 +460,6 @@ ngx_devpoll_process_events(ngx_cycle_t * continue; } -#if 0 - if (c->fd == -1) { - old_cycle = ngx_old_cycles.elts; - for (j = 0; j < ngx_old_cycles.nelts; j++) { - if (old_cycle[j] == NULL) { - continue; - } - c = &old_cycle[j]->connections[event_list[i].fd]; - if (c->fd != -1) { - break; - } - } - } - - if (c->fd == -1) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "unknown cycle"); - exit(1); - } -#endif - revents = event_list[i].revents; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -109,7 +109,9 @@ ngx_poll_init(ngx_cycle_t *cycle) ngx_event_actions = ngx_poll_module_ctx.actions; - ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_ONESHOT_EVENT; + ngx_event_flags = NGX_USE_LEVEL_EVENT + |NGX_USE_ONESHOT_EVENT + |NGX_USE_FD_EVENT; return NGX_OK; } @@ -229,7 +231,7 @@ ngx_poll_del_event(ngx_event_t *ev, int event_list[ev->index] = event_list[nevents]; - c = &ngx_cycle->connections[event_list[nevents].fd]; + c = ngx_cycle->files[event_list[nevents].fd]; if (c->fd == -1) { cycle = ngx_old_cycles.elts; @@ -237,7 +239,7 @@ ngx_poll_del_event(ngx_event_t *ev, int if (cycle[i] == NULL) { continue; } - c = &cycle[i]->connections[event_list[nevents].fd]; + c = cycle[i]->files[event_list[nevents].fd]; if (c->fd != -1) { break; } @@ -425,7 +427,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc continue; } - c = &ngx_cycle->connections[event_list[i].fd]; + c = ngx_cycle->files[event_list[i].fd]; if (c->fd == -1) { old_cycle = ngx_old_cycles.elts; @@ -433,7 +435,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc if (old_cycle[n] == NULL) { continue; } - c = &old_cycle[n]->connections[event_list[i].fd]; + c = old_cycle[n]->files[event_list[i].fd]; if (c->fd != -1) { break; } diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -165,7 +165,9 @@ ngx_rtsig_init(ngx_cycle_t *cycle) ngx_event_actions = ngx_rtsig_module_ctx.actions; - ngx_event_flags = NGX_USE_RTSIG_EVENT|NGX_USE_GREEDY_EVENT; + ngx_event_flags = NGX_USE_RTSIG_EVENT + |NGX_USE_GREEDY_EVENT + |NGX_USE_FD_EVENT; return NGX_OK; } @@ -428,7 +430,7 @@ ngx_rtsig_process_events(ngx_cycle_t *cy /* TODO: old_cycles */ - c = &ngx_cycle->connections[si.si_fd]; + c = ngx_cycle->files[si.si_fd]; instance = signo - rtscf->signo; @@ -596,7 +598,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * break; } - c = &cycle->connections[overflow_current++]; + c = cycle->files[overflow_current++]; if (c->fd == -1) { continue; @@ -652,7 +654,7 @@ ngx_rtsig_process_overflow(ngx_cycle_t * } for (i = 0; i < n; i++) { - c = &cycle->connections[overflow_list[i].fd]; + c = cycle->files[overflow_list[i].fd]; rev = c->read; 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 @@ -113,6 +113,13 @@ static ngx_conf_post_t ngx_accept_mutex static ngx_command_t ngx_event_core_commands[] = { + { ngx_string("worker_connections"), + NGX_EVENT_CONF|NGX_CONF_TAKE1, + ngx_event_connections, + 0, + 0, + NULL }, + { ngx_string("connections"), NGX_EVENT_CONF|NGX_CONF_TAKE1, ngx_event_connections, @@ -322,13 +329,15 @@ ngx_handle_write_event(ngx_event_t *wev, static ngx_int_t ngx_event_module_init(ngx_cycle_t *cycle) { + void ***cf; + ngx_event_conf_t *ecf; #if !(NGX_WIN32) - + char *shared; size_t size; - void ***cf; - char *shared; + ngx_int_t limit; + struct rlimit rlmt; ngx_core_conf_t *ccf; - ngx_event_conf_t *ecf; +#endif cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module); @@ -343,9 +352,30 @@ ngx_event_module_init(ngx_cycle_t *cycle ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "using the \"%s\" event method", ecf->name); +#if !(NGX_WIN32) ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "getrlimit(RLIMIT_NOFILE) failed, ignored"); + + } else { + if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur + && (ccf->rlimit_nofile == NGX_CONF_UNSET + || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile)) + { + limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ? + (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile; + + ngx_log_error(NGX_LOG_WARN, cycle->log, 0, + "%ui worker_connections are more than " + "open file resource limit: %i", + ecf->connections, limit); + } + } + + if (ccf->master == 0 || ngx_accept_mutex_ptr) { return NGX_OK; } @@ -390,7 +420,7 @@ ngx_event_module_init(ngx_cycle_t *cycle "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); -#endif +#endif /* !(NGX_WIN32) */ return NGX_OK; } @@ -400,15 +430,16 @@ static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; - ngx_socket_t fd; ngx_event_t *rev, *wev; - ngx_listening_t *s; - ngx_connection_t *c; + ngx_listening_t *ls; + ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; #if (NGX_WIN32) ngx_iocp_conf_t *iocpcf; +#else + struct rlimit rlmt; #endif ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); @@ -449,28 +480,42 @@ ngx_event_process_init(ngx_cycle_t *cycl } } - cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections, +#if !(NGX_WIN32) + + if (ngx_event_flags & NGX_USE_FD_EVENT) { + + if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "getrlimit(RLIMIT_NOFILE) failed"); + return NGX_ERROR; + } + + cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; + + cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, + cycle->log); + if (cycle->files == NULL) { + return NGX_ERROR; + } + } + +#endif + + cycle->connections0 = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections, cycle->log); - if (cycle->connections == NULL) { + if (cycle->connections0 == NULL) { return NGX_ERROR; } - c = cycle->connections; - for (i = 0; i < cycle->connection_n; i++) { - c[i].fd = (ngx_socket_t) -1; - c[i].data = NULL; -#if (NGX_THREADS) - c[i].lock = 0; -#endif - } + c = cycle->connections0; - cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->read_events0 = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, cycle->log); - if (cycle->read_events == NULL) { + if (cycle->read_events0 == NULL) { return NGX_ERROR; } - rev = cycle->read_events; + rev = cycle->read_events0; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; @@ -480,13 +525,13 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif } - cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->write_events0 = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, cycle->log); - if (cycle->write_events == NULL) { + if (cycle->write_events0 == NULL) { return NGX_ERROR; } - wev = cycle->write_events; + wev = cycle->write_events0; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; #if (NGX_THREADS) @@ -495,41 +540,57 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif } + i = cycle->connection_n; + next = NULL; + + do { + i--; + + c[i].data = next; + c[i].read = &cycle->read_events0[i]; + c[i].write = &cycle->write_events0[i]; + c[i].fd = (ngx_socket_t) -1; + + next = &c[i]; + +#if (NGX_THREADS) + c[i].lock = 0; +#endif + } while (i); + + cycle->free_connections = next; + cycle->free_connection_n = ecf->connections; + /* for each listening socket */ - s = cycle->listening.elts; + ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - fd = s[i].fd; + c = ngx_get_connection(ls[i].fd, cycle->log); -#if (NGX_WIN32) - /* - * Winsock assignes a socket number divisible by 4 - * so to find a connection we divide a socket number by 4. - */ + if (c == NULL) { + return NGX_ERROR; + } - fd /= 4; -#endif - - c = &cycle->connections[fd]; - rev = &cycle->read_events[fd]; - wev = &cycle->write_events[fd]; + rev = c->read; + wev = c->write; ngx_memzero(c, sizeof(ngx_connection_t)); + + c->read = rev; + c->write = wev; + c->fd = ls[i].fd; + c->log = &ls[i].log; + + c->listening = &ls[i]; + ls[i].connection = c; + + c->ctx = ls[i].ctx; + c->servers = ls[i].servers; + ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); - c->fd = s[i].fd; - c->listening = &s[i]; - - c->ctx = s[i].ctx; - c->servers = s[i].servers; - c->log = s[i].log; - c->read = rev; - - /* required by iocp in "c->write->active = 1" */ - c->write = wev; - /* required by poll */ wev->index = NGX_INVALID_INDEX; @@ -542,24 +603,26 @@ ngx_event_process_init(ngx_cycle_t *cycl rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) - rev->deferred_accept = s[i].deferred_accept; + rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { - if (s[i].remain) { + if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ - if (ngx_del_event(&cycle->old_cycle->read_events[fd], - NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) + old = ls[i].previous->connection; + + if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) + == NGX_ERROR) { return NGX_ERROR; } - cycle->old_cycle->connections[fd].fd = (ngx_socket_t) -1; + old->fd = (ngx_socket_t) -1; } } @@ -572,9 +635,11 @@ ngx_event_process_init(ngx_cycle_t *cycl return NGX_ERROR; } + ls[i].log.handler = ngx_acceptex_log_error; + iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); - if (ngx_event_post_acceptex(&s[i], iocpcf->post_acceptex) - == NGX_ERROR) + if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) + == NGX_ERROR) { return NGX_ERROR; } @@ -607,6 +672,7 @@ ngx_event_process_init(ngx_cycle_t *cycl } #endif + } return NGX_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 @@ -218,63 +218,69 @@ extern ngx_event_actions_t ngx_event_a /* - * The event filter requires to read/write the whole data - + * The event filter requires to read/write the whole data: * select, poll, /dev/poll, kqueue, epoll. */ #define NGX_USE_LEVEL_EVENT 0x00000001 /* * The event filter is deleted after a notification without an additional - * syscall - select, poll, kqueue, epoll, Solaris 10's event ports. + * syscall: select, poll, kqueue, epoll, Solaris 10's event ports. */ #define NGX_USE_ONESHOT_EVENT 0x00000002 /* - * The event filter notifies only the changes and an initial level - + * The event filter notifies only the changes and an initial level: * kqueue, epoll. */ #define NGX_USE_CLEAR_EVENT 0x00000004 /* - * The event filter has kqueue features - the eof flag, errno, + * The event filter has kqueue features: the eof flag, errno, * available data, etc. */ -#define NGX_USE_KQUEUE_EVENT 0x00000008 +#define NGX_USE_KQUEUE_EVENT 0x00000008 /* - * The event filter supports low water mark - kqueue's NOTE_LOWAT. + * The event filter supports low water mark: kqueue's NOTE_LOWAT. * kqueue in FreeBSD 4.1-4.2 has no NOTE_LOWAT so we need a separate flag. */ -#define NGX_USE_LOWAT_EVENT 0x00000010 +#define NGX_USE_LOWAT_EVENT 0x00000010 /* - * The event filter requires to do i/o operation until EAGAIN - + * The event filter requires to do i/o operation until EAGAIN: * epoll, rt signals. */ -#define NGX_USE_GREEDY_EVENT 0x00000020 +#define NGX_USE_GREEDY_EVENT 0x00000020 /* - * The event filter is epoll, + * The event filter is epoll. */ #define NGX_USE_EPOLL_EVENT 0x00000040 /* - * No need to add or delete the event filters - rt signals. + * No need to add or delete the event filters: rt signals. */ #define NGX_USE_RTSIG_EVENT 0x00000080 /* - * No need to add or delete the event filters - overlapped, aio_read, + * No need to add or delete the event filters: overlapped, aio_read, * aioread, io_submit. */ #define NGX_USE_AIO_EVENT 0x00000100 /* - * Need to add socket or handle only once - i/o completion port. + * Need to add socket or handle only once: i/o completion port. * It also requires NGX_HAVE_AIO and NGX_USE_AIO_EVENT to be set. */ #define NGX_USE_IOCP_EVENT 0x00000200 +/* + * The event filter has no opaque data and requires file descriptors table: + * poll, /dev/poll, rt signals. + */ +#define NGX_USE_FD_EVENT 0x00000400 + /* @@ -391,13 +397,14 @@ extern ngx_event_actions_t ngx_event_a #define ngx_del_timer ngx_event_del_timer +extern ngx_os_io_t ngx_io; + #define ngx_recv ngx_io.recv #define ngx_recv_chain ngx_io.recv_chain #define ngx_send ngx_io.send #define ngx_send_chain ngx_io.send_chain - #define NGX_EVENT_MODULE 0x544E5645 /* "EVNT" */ #define NGX_EVENT_CONF 0x02000000 @@ -471,6 +478,7 @@ void ngx_event_accept(ngx_event_t *ev); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); +u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); ngx_int_t ngx_handle_read_event(ngx_event_t *rev, u_int flags); @@ -479,7 +487,8 @@ ngx_int_t ngx_handle_write_event(ngx_eve #if (NGX_WIN32) void ngx_event_acceptex(ngx_event_t *ev); -int ngx_event_post_acceptex(ngx_listening_t *ls, int n); +ngx_int_t ngx_event_post_acceptex(ngx_listening_t *ls, ngx_uint_t n); +u_char *ngx_acceptex_log_error(ngx_log_t *log, u_char *buf, size_t len); #endif 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 @@ -9,26 +9,26 @@ #include -static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log); -static u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); +/* the buffer size is enough to hold "struct sockaddr_un" */ +#define NGX_SOCKLEN 512 + + +static void ngx_close_accepted_connection(ngx_connection_t *c); void ngx_event_accept(ngx_event_t *ev) { - ngx_uint_t instance; -#if 0 - ngx_uint_t accepted; -#endif - socklen_t len; - struct sockaddr *sa; + socklen_t sl; ngx_err_t err; ngx_log_t *log; - ngx_pool_t *pool; + ngx_uint_t instance; ngx_socket_t s; ngx_event_t *rev, *wev; - ngx_connection_t *c, *ls; + ngx_listening_t *ls; + ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; + char sa[NGX_SOCKLEN]; ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); @@ -39,77 +39,28 @@ ngx_event_accept(ngx_event_t *ev) ev->available = ecf->multi_accept; } - ls = ev->data; + lc = ev->data; + ls = lc->listening; + ev->ready = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "accept on %V, ready: %d", - &ls->listening->addr_text, ev->available); - - ev->ready = 0; - pool = NULL; -#if 0 - accepted = 0; -#endif + "accept on %V, ready: %d", &ls->addr_text, ev->available); do { - - if (pool == NULL) { - - /* - * Create the pool before accept() to avoid the copying of - * the sockaddr. Although accept() can fail it is uncommon - * case and besides the pool can be got from the free pool list. - */ - - pool = ngx_create_pool(ls->listening->pool_size, ev->log); - if (pool == NULL) { - return; - } - } + sl = NGX_SOCKLEN; - sa = ngx_palloc(pool, ls->listening->socklen); - if (sa == NULL) { - ngx_destroy_pool(pool); - return; - } - - log = ngx_palloc(pool, sizeof(ngx_log_t)); - if (log == NULL) { - ngx_destroy_pool(pool); - return; - } - - ngx_memcpy(log, ls->log, sizeof(ngx_log_t)); - pool->log = log; - - log->data = &ls->listening->addr_text; - log->handler = ngx_accept_log_error; - - len = ls->listening->socklen; - - s = accept(ls->fd, sa, &len); + s = accept(lc->fd, (struct sockaddr *) sa, &sl); if (s == -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { -#if 0 - if (!(ngx_event_flags & NGX_USE_RTSIG_EVENT)) - { - ngx_log_error(NGX_LOG_NOTICE, log, err, - "EAGAIN after %d accepted connection(s)", - accepted); - } -#endif - - ngx_destroy_pool(pool); return; } ngx_log_error((err == NGX_ECONNABORTED) ? NGX_LOG_CRIT: NGX_LOG_ALERT, - ev->log, err, - "accept() on %V failed", &ls->listening->addr_text); + ev->log, err, "accept() failed"); if (err == NGX_ECONNABORTED) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -117,12 +68,10 @@ ngx_event_accept(ngx_event_t *ev) } if (ev->available) { - /* reuse the previously allocated pool */ continue; } } - ngx_destroy_pool(pool); return; } @@ -131,34 +80,58 @@ ngx_event_accept(ngx_event_t *ev) ngx_atomic_inc(ngx_stat_active); #endif - ngx_accept_disabled = (ngx_uint_t) s + NGX_ACCEPT_THRESHOLD - - ecf->connections; + ngx_accept_disabled = NGX_ACCEPT_THRESHOLD + - ngx_cycle->free_connection_n; + + c = ngx_get_connection(s, ev->log); - /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */ + if (c == NULL) { + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } - if ((ngx_uint_t) s >= ecf->connections) { + return; + } + + rev = c->read; + wev = c->write; + + ngx_memzero(c, sizeof(ngx_connection_t)); - ngx_log_error(NGX_LOG_ALERT, ev->log, 0, - "accept() on %V returned socket #%d while " - "only %d connections was configured, " - "closing the connection", - &ls->listening->addr_text, s, ecf->connections); + c->read = rev; + c->write = wev; + c->fd = s; + c->log = ev->log; + + c->pool = ngx_create_pool(ls->pool_size, ev->log); + if (c->pool == NULL) { + ngx_close_accepted_connection(c); + return; + } - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + c->sockaddr = ngx_palloc(c->pool, sl); + if (c->sockaddr == NULL) { + ngx_close_accepted_connection(c); + return; + } + + ngx_memcpy(c->sockaddr, sa, sl); + + log = ngx_palloc(c->pool, sizeof(ngx_log_t)); + if (log == NULL) { + ngx_close_accepted_connection(c); return; } /* set a blocking mode for aio and non-blocking mode for others */ if (ngx_inherited_nonblocking) { - if ((ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (ngx_event_flags & NGX_USE_AIO_EVENT) { if (ngx_blocking(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " failed"); - - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + ngx_close_accepted_connection(c); return; } } @@ -166,61 +139,35 @@ ngx_event_accept(ngx_event_t *ev) } else { if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) { if (ngx_nonblocking(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + ngx_close_accepted_connection(c); return; } } } -#if (NGX_WIN32) - /* - * Winsock assignes a socket number divisible by 4 - * so to find a connection we divide a socket number by 4. - */ + *log = ls->log; + + c->recv = ngx_recv; + c->send = ngx_send; + c->send_chain = ngx_send_chain; - if (s % 4) { - ngx_log_error(NGX_LOG_EMERG, ev->log, 0, - "accept() on %V returned socket #%d, " - "not divisible by 4", - &ls->listening->addr_text, s); - exit(1); - } + c->log = log; + c->pool->log = log; - c = &ngx_cycle->connections[s / 4]; - rev = &ngx_cycle->read_events[s / 4]; - wev = &ngx_cycle->write_events[s / 4]; -#else - c = &ngx_cycle->connections[s]; - rev = &ngx_cycle->read_events[s]; - wev = &ngx_cycle->write_events[s]; -#endif + c->listening = ls; + c->socklen = sl; + + c->unexpected_eof = 1; + + c->ctx = lc->ctx; + c->servers = lc->servers; instance = rev->instance; -#if (NGX_THREADS) - - if (*(&c->lock)) { - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "spinlock in accept, fd:%d", s); - ngx_spinlock(&c->lock, 1000); - ngx_unlock(&c->lock); - } - -#endif - ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); - ngx_memzero(c, sizeof(ngx_connection_t)); - - c->pool = pool; - - c->listening = ls->listening; - c->sockaddr = sa; - c->socklen = len; rev->instance = !instance; wev->instance = !instance; @@ -231,12 +178,6 @@ ngx_event_accept(ngx_event_t *ev) rev->data = c; wev->data = c; - c->read = rev; - c->write = wev; - - c->fd = s; - c->unexpected_eof = 1; - wev->write = 1; wev->ready = 1; @@ -252,14 +193,6 @@ ngx_event_accept(ngx_event_t *ev) #endif } - c->ctx = ls->ctx; - c->servers = ls->servers; - - c->recv = ngx_recv; - c->send = ngx_send; - c->send_chain = ngx_send_chain; - - c->log = log; rev->log = log; wev->log = log; @@ -285,24 +218,21 @@ ngx_event_accept(ngx_event_t *ev) wev->own_lock = &c->lock; #endif - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0, "accept: fd:%d c:%d", s, c->number); - if (c->listening->addr_ntop) { - c->addr_text.data = ngx_palloc(c->pool, - c->listening->addr_text_max_len); + if (ls->addr_ntop) { + c->addr_text.data = ngx_palloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + ngx_close_accepted_connection(c); return; } - c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, + c->addr_text.len = ngx_sock_ntop(ls->family, c->sockaddr, c->addr_text.data, - c->listening->addr_text_max_len); + ls->addr_text_max_len); if (c->addr_text.len == 0) { - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + ngx_close_accepted_connection(c); return; } } @@ -328,27 +258,20 @@ ngx_event_accept(ngx_event_t *ev) if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { - ngx_close_accepted_socket(s, log); - ngx_destroy_pool(pool); + ngx_close_accepted_connection(c); return; } } - pool = NULL; - log->data = NULL; log->handler = NULL; - ls->listening->handler(c); + ls->handler(c); if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } -#if 0 - accepted++; -#endif - } while (ev->available); } @@ -389,27 +312,22 @@ ngx_trylock_accept_mutex(ngx_cycle_t *cy ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle) { - ngx_uint_t i; - ngx_listening_t *s; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_connection_t *c; - s = cycle->listening.elts; + ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - /* - * we do not need to handle the Winsock sockets here (divide a socket - * number by 4) because this function would never called - * in the Winsock environment - */ + c = ls[i].connection; if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (ngx_add_conn(&cycle->connections[s[i].fd]) == NGX_ERROR) { + if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { - if (ngx_add_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT, 0) - == NGX_ERROR) - { + if (ngx_add_event(c->read, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } @@ -422,36 +340,27 @@ ngx_enable_accept_events(ngx_cycle_t *cy ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle) { - ngx_uint_t i; - ngx_listening_t *s; + ngx_uint_t i; + ngx_listening_t *ls; + ngx_connection_t *c; - s = cycle->listening.elts; + ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - /* - * we do not need to handle the Winsock sockets here (divide a socket - * number by 4) because this function would never called - * in the Winsock environment - */ + c = ls[i].connection; + + if (!c->read->active) { + continue; + } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - if (!cycle->connections[s[i].fd].read->active) { - continue; - } - - if (ngx_del_conn(&cycle->connections[s[i].fd], NGX_DISABLE_EVENT) - == NGX_ERROR) - { + if (ngx_del_conn(c, NGX_DISABLE_EVENT) == NGX_ERROR) { return NGX_ERROR; } } else { - if (!cycle->read_events[s[i].fd].active) { - continue; - } - - if (ngx_del_event(&cycle->read_events[s[i].fd], NGX_READ_EVENT, - NGX_DISABLE_EVENT) == NGX_ERROR) + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) { return NGX_ERROR; } @@ -463,21 +372,33 @@ ngx_disable_accept_events(ngx_cycle_t *c static void -ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log) +ngx_close_accepted_connection(ngx_connection_t *c) { - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_socket_t fd; + + ngx_free_connection(c); + + fd = c->fd; + c->fd = (ngx_socket_t) -1; + + if (ngx_close_socket(fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_close_socket_n " failed"); } + if (c->pool) { + ngx_destroy_pool(c->pool); + } + #if (NGX_STAT_STUB) ngx_atomic_dec(ngx_stat_active); #endif } -static u_char * +u_char * ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len) { - return ngx_snprintf(buf, len, " while accept() on %V", log->data); + return ngx_snprintf(buf, len, " while accepting new connection on %V", + log->data); } diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -10,22 +10,18 @@ #include -#define NGX_RESOLVER_BUFSIZE 8192 - - ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { - int rc; - ngx_uint_t instance, level; - u_int event; - time_t now; - ngx_err_t err; - ngx_peer_t *peer; - ngx_socket_t s; - ngx_event_t *rev, *wev; - ngx_connection_t *c; - ngx_event_conf_t *ecf; + int rc; + ngx_uint_t instance, level, i; + u_int event; + time_t now; + ngx_err_t err; + ngx_peer_t *peer; + ngx_socket_t s; + ngx_event_t *rev, *wev; + ngx_connection_t *c; now = ngx_time(); @@ -47,6 +43,7 @@ ngx_event_connect_peer(ngx_peer_connecti pc->connection = c; pc->cached = 1; + return NGX_OK; } @@ -102,9 +99,16 @@ ngx_event_connect_peer(ngx_peer_connecti pc->tries--; if (pc->tries == 0) { + + /* all peers failed, mark them as live for quick recovery */ + + for (i = 0; i < pc->peers->number; i++) { + pc->peers->peer[i].fails = 0; + } + /* ngx_unlock_mutex(pc->peers->mutex); */ - return NGX_ERROR; + return NGX_BUSY; } } } @@ -124,27 +128,26 @@ ngx_event_connect_peer(ngx_peer_connecti } - ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); - - /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */ - - if ((ngx_uint_t) s >= ecf->connections) { + c = ngx_get_connection(s, pc->log); - ngx_log_error(NGX_LOG_ALERT, pc->log, 0, - "socket() returned socket #%d while only %d " - "connections was configured, closing the socket", - s, ecf->connections); - + if (c == NULL) { if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n "failed"); } - /* TODO: sleep for some time */ - return NGX_ERROR; } + rev = c->read; + wev = c->write; + + ngx_memzero(c, sizeof(ngx_connection_t)); + + c->read = rev; + c->write = wev; + c->fd = s; + c->log = pc->log; if (pc->rcvbuf) { if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, @@ -152,6 +155,8 @@ ngx_event_connect_peer(ngx_peer_connecti ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); + ngx_free_connection(c); + if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n " failed"); @@ -165,6 +170,8 @@ ngx_event_connect_peer(ngx_peer_connecti ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); + ngx_free_connection(c); + if (ngx_close_socket(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_close_socket_n " failed"); @@ -173,46 +180,19 @@ ngx_event_connect_peer(ngx_peer_connecti return NGX_ERROR; } -#if (NGX_WIN32) + c->recv = ngx_recv; + c->send = ngx_send; + c->send_chain = ngx_send_chain; - /* - * Winsock assignes a socket number divisible by 4 - * so to find a connection we divide a socket number by 4. - */ + c->log_error = pc->log_error; - if (s % 4) { - ngx_log_error(NGX_LOG_EMERG, pc->log, 0, - ngx_socket_n - " created socket %d, not divisible by 4", s); - exit(1); + if (peer->sockaddr->sa_family != AF_INET) { + c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; + c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; } - c = &ngx_cycle->connections[s / 4]; - rev = &ngx_cycle->read_events[s / 4]; - wev = &ngx_cycle->write_events[s / 4]; - -#else - - c = &ngx_cycle->connections[s]; - rev = &ngx_cycle->read_events[s]; - wev = &ngx_cycle->write_events[s]; - -#endif - instance = rev->instance; -#if (NGX_THREADS) - - if (*(&c->lock)) { - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "spinlock in connect, fd:%d", s); - ngx_spinlock(&c->lock, 1000); - ngx_unlock(&c->lock); - } - -#endif - - ngx_memzero(c, sizeof(ngx_connection_t)); ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); @@ -225,27 +205,11 @@ ngx_event_connect_peer(ngx_peer_connecti rev->data = c; wev->data = c; - c->read = rev; - c->write = wev; wev->write = 1; - c->recv = ngx_recv; - c->send = ngx_send; - c->send_chain = ngx_send_chain; - - c->log = pc->log; rev->log = pc->log; wev->log = pc->log; - c->fd = s; - - c->log_error = pc->log_error; - - if (peer->sockaddr->sa_family != AF_INET) { - c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; - c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; - } - pc->connection = c; /* @@ -272,8 +236,8 @@ ngx_event_connect_peer(ngx_peer_connecti } } - ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "connect to %V, #%d", &peer->name, c->number); + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, + "connect to %V, fd:%d #%d", &peer->name, s, c->number); rc = connect(s, peer->sockaddr, peer->socklen); @@ -293,7 +257,7 @@ ngx_event_connect_peer(ngx_peer_connecti ngx_log_error(level, c->log, err, "connect() to %V failed", &peer->name); - return NGX_CONNECT_ERROR; + return NGX_DECLINED; } } diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -13,9 +13,6 @@ #include -#define NGX_CONNECT_ERROR -10 - - typedef struct { struct sockaddr *sockaddr; socklen_t socklen; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -81,7 +81,7 @@ ngx_ssl_init(ngx_log_t *log) ngx_int_t -ngx_ssl_create_session(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c, +ngx_ssl_create_connection(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c, ngx_uint_t flags) { ngx_ssl_t *ssl; @@ -91,28 +91,28 @@ ngx_ssl_create_session(ngx_ssl_ctx_t *ss return NGX_ERROR; } - ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); - if (ssl->buf == NULL) { - return NGX_ERROR; + if (flags & NGX_SSL_BUFFER) { + ssl->buffer = 1; + + ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + if (ssl->buf == NULL) { + return NGX_ERROR; + } } - if (flags & NGX_SSL_BUFFER) { - ssl->buffer = 1; - } + ssl->connection = SSL_new(ssl_ctx); - ssl->ssl = SSL_new(ssl_ctx); - - if (ssl->ssl == NULL) { + if (ssl->connection == NULL) { ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); return NGX_ERROR; } - if (SSL_set_fd(ssl->ssl, c->fd) == 0) { + if (SSL_set_fd(ssl->connection, c->fd) == 0) { ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed"); return NGX_ERROR; } - SSL_set_accept_state(ssl->ssl); + SSL_set_accept_state(ssl->connection); c->ssl = ssl; @@ -138,7 +138,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char for ( ;; ) { - n = SSL_read(c->ssl->ssl, buf, size); + n = SSL_read(c->ssl->connection, buf, size); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); @@ -148,13 +148,14 @@ ngx_ssl_recv(ngx_connection_t *c, u_char #if (NGX_DEBUG) - if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) { + if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) + { char buf[129], *s, *d; SSL_CIPHER *cipher; c->ssl->handshaked = 1; - cipher = SSL_get_current_cipher(c->ssl->ssl); + cipher = SSL_get_current_cipher(c->ssl->connection); if (cipher) { SSL_CIPHER_description(cipher, &buf[1], 128); @@ -179,6 +180,12 @@ ngx_ssl_recv(ngx_connection_t *c, u_char ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL cipher: \"%s\"", &buf[1]); + + if (SSL_session_reused(c->ssl->connection)) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL reused session"); + } + } else { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL no shared ciphers"); @@ -214,9 +221,10 @@ ngx_ssl_recv(ngx_connection_t *c, u_char static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n) { - int sslerr; - ngx_err_t err; - char *handshake; + int sslerr; + char *handshake; + ngx_err_t err; + ngx_uint_t level; if (n > 0) { @@ -242,14 +250,14 @@ ngx_ssl_handle_recv(ngx_connection_t *c, return NGX_OK; } - if (!SSL_is_init_finished(c->ssl->ssl)) { + if (!SSL_is_init_finished(c->ssl->connection)) { handshake = " in SSL handshake"; } else { handshake = ""; } - sslerr = SSL_get_error(c->ssl->ssl, n); + sslerr = SSL_get_error(c->ssl->connection, n); err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; @@ -264,7 +272,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c, ngx_log_error(NGX_LOG_INFO, c->log, err, "client does SSL %shandshake", - SSL_is_init_finished(c->ssl->ssl) ? "re" : ""); + SSL_is_init_finished(c->ssl->connection) ? "re" : ""); c->write->ready = 0; @@ -294,8 +302,34 @@ ngx_ssl_handle_recv(ngx_connection_t *c, return NGX_ERROR; } - ngx_ssl_error(NGX_LOG_ALERT, c->log, err, - "SSL_read() failed%s", handshake); + level = NGX_LOG_CRIT; + + if (sslerr == SSL_ERROR_SYSCALL) { + + if (err == NGX_ECONNRESET + || err == NGX_EPIPE + || err == NGX_ENOTCONN + || err == NGX_ECONNREFUSED + || err == NGX_EHOSTUNREACH) + { + switch (c->log_error) { + + case NGX_ERROR_IGNORE_ECONNRESET: + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + break; + } + } + } + + ngx_ssl_error(level, c->log, err, "SSL_read() failed%s", handshake); return NGX_ERROR; } @@ -448,12 +482,13 @@ ngx_ssl_send_chain(ngx_connection_t *c, ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) { - int n, sslerr; - ngx_err_t err; + int n, sslerr; + ngx_err_t err; + ngx_uint_t level; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); - n = SSL_write(c->ssl->ssl, data, size); + n = SSL_write(c->ssl->connection, data, size); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n); @@ -461,13 +496,13 @@ ngx_ssl_write(ngx_connection_t *c, u_cha #if (NGX_DEBUG) - if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) { + if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) { char buf[129], *s, *d; SSL_CIPHER *cipher; c->ssl->handshaked = 1; - cipher = SSL_get_current_cipher(c->ssl->ssl); + cipher = SSL_get_current_cipher(c->ssl->connection); if (cipher) { SSL_CIPHER_description(cipher, &buf[1], 128); @@ -492,6 +527,12 @@ ngx_ssl_write(ngx_connection_t *c, u_cha ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL cipher: \"%s\"", &buf[1]); + + if (SSL_session_reused(c->ssl->connection)) { + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL reused session"); + } + } else { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL no shared ciphers"); @@ -521,7 +562,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha return n; } - sslerr = SSL_get_error(c->ssl->ssl, n); + sslerr = SSL_get_error(c->ssl->connection, n); err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; @@ -536,7 +577,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha ngx_log_error(NGX_LOG_INFO, c->log, err, "client does SSL %shandshake", - SSL_is_init_finished(c->ssl->ssl) ? "re" : ""); + SSL_is_init_finished(c->ssl->connection) ? "re" : ""); c->read->ready = 0; @@ -560,7 +601,34 @@ ngx_ssl_write(ngx_connection_t *c, u_cha c->ssl->no_rcv_shut = 1; c->ssl->no_send_shut = 1; - ngx_ssl_error(NGX_LOG_ALERT, c->log, err, "SSL_write() failed"); + level = NGX_LOG_CRIT; + + if (sslerr == SSL_ERROR_SYSCALL) { + + if (err == NGX_ECONNRESET + || err == NGX_EPIPE + || err == NGX_ENOTCONN + || err == NGX_ECONNREFUSED + || err == NGX_EHOSTUNREACH) + { + switch (c->log_error) { + + case NGX_ERROR_IGNORE_ECONNRESET: + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + break; + } + } + } + + ngx_ssl_error(level, c->log, err, "SSL_write() failed"); return NGX_ERROR; } @@ -602,7 +670,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) } if (mode) { - SSL_set_shutdown(c->ssl->ssl, mode); + SSL_set_shutdown(c->ssl->connection, mode); c->ssl->shutdown_set = 1; } } @@ -613,13 +681,14 @@ ngx_ssl_shutdown(ngx_connection_t *c) #endif for ( ;; ) { - n = SSL_shutdown(c->ssl->ssl); + n = SSL_shutdown(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); if (n == 1 || (n == 0 && c->read->timedout)) { - SSL_free(c->ssl->ssl); + SSL_free(c->ssl->connection); c->ssl = NULL; + return NGX_OK; } @@ -632,7 +701,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) } if (!again) { - sslerr = SSL_get_error(c->ssl->ssl, n); + sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); @@ -660,6 +729,9 @@ ngx_ssl_shutdown(ngx_connection_t *c) ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); + SSL_free(c->ssl->connection); + c->ssl = NULL; + return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -23,7 +23,7 @@ typedef struct { - SSL *ssl; + SSL *connection; ngx_int_t last; ngx_buf_t *buf; ngx_event_handler_pt saved_read_handler; @@ -49,8 +49,8 @@ typedef SSL_CTX ngx_ssl_ctx_t; ngx_int_t ngx_ssl_init(ngx_log_t *log); -ngx_int_t ngx_ssl_create_session(ngx_ssl_ctx_t *ctx, ngx_connection_t *c, - ngx_uint_t flags); +ngx_int_t ngx_ssl_create_connection(ngx_ssl_ctx_t *ctx, ngx_connection_t *c, + ngx_uint_t flags); #define ngx_ssl_handshake(c) NGX_OK diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -203,7 +203,10 @@ ngx_http_autoindex_handler(ngx_http_requ if (ngx_open_dir(&dname, &dir) == NGX_ERROR) { err = ngx_errno; - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { + if (err == NGX_ENOENT + || err == NGX_ENOTDIR + || err == NGX_ENAMETOOLONG) + { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -82,7 +82,10 @@ ngx_http_headers_filter(ngx_http_request ngx_table_elt_t *expires, *cc, **ccp; ngx_http_headers_conf_t *conf; - if (r->headers_out.status != NGX_HTTP_OK || r->main) { + if ((r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_NOT_MODIFIED) + || r->main) + { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -160,7 +160,7 @@ static ngx_command_t ngx_http_proxy_com NULL }, { ngx_string("proxy_pass_unparsed_uri"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.pass_unparsed_uri), diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -83,6 +83,9 @@ ngx_module_t ngx_http_ssl_module = { }; +static u_char ngx_http_session_id_ctx[] = "HTTP"; + + static void * ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { @@ -147,12 +150,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } -#if 0 - SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); - SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3); - SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_SINGLE_DH_USE); -#endif - if (conf->ciphers.len) { if (SSL_CTX_set_cipher_list(conf->ssl_ctx, (const char *) conf->ciphers.data) == 0) @@ -182,7 +179,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * return NGX_CONF_ERROR; } - SSL_CTX_set_verify(conf->ssl_ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); + + SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + SSL_CTX_set_read_ahead(conf->ssl_ctx, 1); + + SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER); + + SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_http_session_id_ctx, + sizeof(ngx_http_session_id_ctx) - 1); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -203,7 +203,10 @@ ngx_http_static_handler(ngx_http_request if (fd == NGX_INVALID_FILE) { err = ngx_errno; - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { + if (err == NGX_ENOENT + || err == NGX_ENOTDIR + || err == NGX_ENAMETOOLONG) + { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; 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 @@ -646,7 +646,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ls->post_accept_timeout = cscf->client_header_timeout; clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - ls->log = clcf->err_log; + + ls->log = *clcf->err_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; #if (NGX_WIN32) iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); 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 @@ -284,6 +284,13 @@ static ngx_command_t ngx_http_core_comm 0, NULL }, + { ngx_string("satisfy_any"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, satisfy_any), + NULL }, + { ngx_string("internal"), NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, ngx_http_core_internal, @@ -401,50 +408,43 @@ ngx_http_handler(ngx_http_request_t *r) r->connection->unexpected_eof = 0; - switch (r->headers_in.connection_type) { - case 0: - if (r->http_version > NGX_HTTP_VERSION_10) { + if (r->err_ctx == NULL) { + switch (r->headers_in.connection_type) { + case 0: + if (r->http_version > NGX_HTTP_VERSION_10) { + r->keepalive = 1; + } else { + r->keepalive = 0; + } + break; + + case NGX_HTTP_CONNECTION_CLOSE: + r->keepalive = 0; + break; + + case NGX_HTTP_CONNECTION_KEEP_ALIVE: r->keepalive = 1; - } else { + break; + } + + if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) { + + /* + * MSIE may wait for some time if the response for the POST request + * is sent over the keepalive connection + */ + r->keepalive = 0; } - break; - - case NGX_HTTP_CONNECTION_CLOSE: - r->keepalive = 0; - break; - - case NGX_HTTP_CONNECTION_KEEP_ALIVE: - r->keepalive = 1; - break; + + if (r->headers_in.content_length_n > 0) { + r->lingering_close = 1; + + } else { + r->lingering_close = 0; + } } - if (r->keepalive && r->headers_in.msie && r->method == NGX_HTTP_POST) { - - /* - * MSIE may wait for some time if the response for the POST request - * is sent over the keepalive connection - */ - - r->keepalive = 0; - } - -#if 0 - /* TEST STUB */ r->http_version = NGX_HTTP_VERSION_10; - /* TEST STUB */ r->keepalive = 0; -#endif - - if (r->headers_in.content_length_n > 0) { - r->lingering_close = 1; - - } else { - r->lingering_close = 0; - } - -#if 0 - /* TEST STUB */ r->lingering_close = 1; -#endif - r->write_event_handler = ngx_http_core_run_phases; r->valid_unparsed_uri = 1; @@ -498,6 +498,10 @@ ngx_http_core_run_phases(ngx_http_reques r->phase = NGX_HTTP_FIND_CONFIG_PHASE; } + if (r->phase == NGX_HTTP_ACCESS_PHASE && r->main) { + continue; + } + if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) { r->write_event_handler = ngx_http_request_empty_handler; ngx_http_finalize_request(r, r->content_handler(r)); @@ -515,7 +519,7 @@ ngx_http_core_run_phases(ngx_http_reques /* * we should never use r here because - * it could point to already freed data + * it may point to already freed data */ return; @@ -525,6 +529,30 @@ ngx_http_core_run_phases(ngx_http_reques continue; } + if (r->phase == NGX_HTTP_ACCESS_PHASE) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->satisfy_any) { + + if (rc == NGX_OK) { + r->access_code = 0; + + if (r->headers_out.www_authenticate) { + r->headers_out.www_authenticate->hash = 0; + } + + break; + } + + if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) + { + r->access_code = rc; + + continue; + } + } + } + if (rc >= NGX_HTTP_SPECIAL_RESPONSE || rc == NGX_HTTP_NO_CONTENT || rc == NGX_ERROR) @@ -545,6 +573,12 @@ ngx_http_core_run_phases(ngx_http_reques if (rc == NGX_OK && cmcf->phases[r->phase].type == NGX_OK) { break; } + + } + + if (r->phase == NGX_HTTP_ACCESS_PHASE && r->access_code) { + ngx_http_finalize_request(r, r->access_code); + return; } } @@ -1102,6 +1136,7 @@ ngx_http_subrequest(ngx_http_request_t * sr->internal = 1; + sr->discard_body = r->discard_body; sr->main_filter_need_in_memory = r->main_filter_need_in_memory; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1793,6 +1828,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->client_max_body_size = NGX_CONF_UNSET_SIZE; lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; lcf->client_body_timeout = NGX_CONF_UNSET_MSEC; + lcf->satisfy_any = NGX_CONF_UNSET; lcf->internal = NGX_CONF_UNSET; lcf->sendfile = NGX_CONF_UNSET; lcf->tcp_nopush = NGX_CONF_UNSET; @@ -1895,6 +1931,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 60000); + ngx_conf_merge_value(conf->satisfy_any, prev->satisfy_any, 0); ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0); 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 @@ -217,6 +217,7 @@ struct ngx_http_core_loc_conf_s { time_t keepalive_header; /* keepalive_timeout */ + ngx_flag_t satisfy_any; /* satisfy_any */ ngx_flag_t internal; /* internal */ ngx_flag_t sendfile; /* sendfile */ ngx_flag_t tcp_nopush; /* tcp_nopush */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -359,7 +359,7 @@ void ngx_http_init_request(ngx_event_t * if (sscf->enable) { if (c->ssl == NULL) { - if (ngx_ssl_create_session(sscf->ssl_ctx, c, NGX_SSL_BUFFER) + if (ngx_ssl_create_connection(sscf->ssl_ctx, c, NGX_SSL_BUFFER) == NGX_ERROR) { ngx_http_close_connection(c); @@ -1732,10 +1732,6 @@ ngx_http_postponed_handler(ngx_http_requ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http postponed output filter: %d", rc); - if (rc == NGX_AGAIN) { - return rc; - } - /* * we treat NGX_ERROR as NGX_OK, because we need to complete * all postponed requests @@ -1744,6 +1740,11 @@ ngx_http_postponed_handler(ngx_http_requ pr = r->postponed; if (pr == NULL) { + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + return NGX_OK; } } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -307,6 +307,7 @@ struct ngx_http_request_s { ngx_uint_t phase; ngx_int_t phase_handler; ngx_http_handler_pt content_handler; + ngx_uint_t access_code; ngx_http_variable_value_t **variables; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -459,7 +459,11 @@ ngx_http_upstream_connect(ngx_http_reque u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name; - if (rc == NGX_CONNECT_ERROR) { + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); + } + + if (rc == NGX_BUSY || rc == NGX_DECLINED) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; } diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -101,6 +101,8 @@ typedef struct { unsigned quit:1; unsigned protocol:1; unsigned quoted:1; + unsigned backslash:1; + unsigned no_sync_literal:1; ngx_str_t login; ngx_str_t passwd; diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -150,7 +150,8 @@ ngx_imap_auth_http_init(ngx_imap_session rc = ngx_event_connect_peer(&ctx->peer); - if (rc == NGX_ERROR || rc == NGX_CONNECT_ERROR) { + if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + ngx_close_connection(ctx->peer.connection); ngx_imap_session_internal_server_error(s); return; } @@ -448,6 +449,7 @@ ngx_imap_auth_http_process_headers(ngx_i p = ngx_pcalloc(s->connection->pool, size); if (p == NULL) { + ngx_close_connection(ctx->peer.connection); ngx_imap_session_internal_server_error(s); return; } @@ -641,8 +643,9 @@ ngx_imap_auth_http_process_headers(ngx_i static void ngx_imap_auth_sleep_handler(ngx_event_t *rev) { - ngx_connection_t *c; - ngx_imap_session_t *s; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_core_srv_conf_t *cscf; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap auth sleep handler"); @@ -662,6 +665,18 @@ ngx_imap_auth_sleep_handler(ngx_event_t s->connection->read->handler = ngx_imap_auth_state; } + c->log->action = "in auth state"; + + ngx_imap_send(s->connection->write); + + if (c->closed) { + return; + } + + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + + ngx_add_timer(rev, cscf->timeout); + if (rev->ready) { s->connection->read->handler(rev); return; @@ -671,8 +686,6 @@ ngx_imap_auth_sleep_handler(ngx_event_t ngx_imap_close_connection(s->connection); } - ngx_imap_send(s->connection->write); - return; } diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c --- a/src/imap/ngx_imap_core_module.c +++ b/src/imap/ngx_imap_core_module.c @@ -418,7 +418,9 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx ls->ctx = cf->ctx; /* STUB */ - ls->log = cf->cycle->new_log; + ls->log = *cf->cycle->new_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; /**/ return NGX_CONF_OK; diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -33,6 +33,7 @@ static ngx_str_t internal_server_errors static u_char pop3_ok[] = "+OK" CRLF; static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; +static u_char imap_star[] = "* "; static u_char imap_ok[] = "OK completed" CRLF; static u_char imap_next[] = "+ OK" CRLF; static u_char imap_bye[] = "* BYE" CRLF; @@ -42,26 +43,48 @@ static u_char imap_invalid_command[] = void ngx_imap_init_connection(ngx_connection_t *c) { - ngx_imap_log_ctx_t *ctx; + ngx_imap_log_ctx_t *lctx; +#if (NGX_IMAP_SSL) + ngx_imap_conf_ctx_t *ctx; + ngx_imap_ssl_conf_t *sslcf; +#endif ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection"); - ctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t)); - if (ctx == NULL) { + lctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t)); + if (lctx == NULL) { ngx_imap_close_connection(c); return; } - ctx->client = &c->addr_text; - ctx->session = NULL; + lctx->client = &c->addr_text; + lctx->session = NULL; c->log->connection = c->number; c->log->handler = ngx_imap_log_error; - c->log->data = ctx; + c->log->data = lctx; c->log->action = "sending client greeting line"; c->log_error = NGX_ERROR_INFO; +#if (NGX_IMAP_SSL) + + ctx = c->ctx; + sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module); + + if (sslcf->enable) { + if (ngx_ssl_create_connection(sslcf->ssl_ctx, c, 0) == NGX_ERROR) { + ngx_imap_close_connection(c); + return; + } + + c->recv = ngx_ssl_recv; + c->send = ngx_ssl_write; + c->send_chain = ngx_ssl_send_chain; + } + +#endif + ngx_imap_init_session(c->read); } @@ -76,27 +99,15 @@ ngx_imap_init_session(ngx_event_t *rev) ngx_imap_core_srv_conf_t *cscf; #if (NGX_IMAP_SSL) ngx_int_t rc; - ngx_imap_ssl_conf_t *sslcf; #endif c = rev->data; - ctx = c->ctx; - cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); #if (NGX_IMAP_SSL) - sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module); - - if (sslcf->enable) { - - if (ngx_ssl_create_session(sslcf->ssl_ctx, c, NGX_SSL_BUFFER) - == NGX_ERROR) - { - ngx_imap_close_connection(c); - return; - } + if (c->ssl) { rc = ngx_ssl_handshake(c); @@ -116,9 +127,6 @@ ngx_imap_init_session(ngx_event_t *rev) return; } - c->recv = ngx_ssl_recv; - c->send = ngx_ssl_write; - c->send_chain = ngx_ssl_send_chain; } #endif @@ -275,11 +283,11 @@ ngx_imap_init_protocol(ngx_event_t *rev) void ngx_imap_auth_state(ngx_event_t *rev) { - u_char *text, *last, *p; + u_char *text, *last, *p, *dst, *src, *end; ssize_t text_len, last_len; ngx_str_t *arg; ngx_int_t rc; - ngx_uint_t tag; + ngx_uint_t tag, i; ngx_connection_t *c; ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; @@ -324,6 +332,27 @@ ngx_imap_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth command: %i", s->command); + if (s->backslash) { + + arg = s->args.elts; + + for (i = 0; i < s->args.nelts; i++) { + dst = arg[i].data; + end = dst + arg[i].len; + + for (src = dst; src < end; dst++) { + *dst = *src; + if (*src++ == '\\') { + *dst = *src++; + } + } + + arg[i].len = dst - arg[i].data; + } + + s->backslash = 0; + } + switch (s->command) { case NGX_IMAP_LOGIN: @@ -405,6 +434,11 @@ ngx_imap_auth_state(ngx_event_t *rev) } if (tag) { + if (s->tag.len == 0) { + s->tag.len = sizeof(imap_star) - 1; + s->tag.data = (u_char *) imap_star; + } + if (s->tagged_line.len < s->tag.len + text_len + last_len) { s->tagged_line.len = s->tag.len + text_len + last_len; s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len); @@ -693,6 +727,8 @@ ngx_imap_close_connection(ngx_connection #endif + c->closed = 1; + pool = c->pool; ngx_close_connection(c); diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c --- a/src/imap/ngx_imap_parse.c +++ b/src/imap/ngx_imap_parse.c @@ -20,7 +20,9 @@ ngx_int_t ngx_imap_parse_command(ngx_ima sw_command, sw_spaces_before_argument, sw_argument, + sw_backslash, sw_literal, + sw_no_sync_literal_argument, sw_start_literal_argument, sw_literal_argument, sw_end_literal_argument, @@ -225,6 +227,22 @@ ngx_int_t ngx_imap_parse_command(ngx_ima goto done; } break; + case '\\': + if (s->quoted) { + s->backslash = 1; + state = sw_backslash; + } + break; + } + break; + + case sw_backslash: + switch (ch) { + case CR: + case LF: + goto invalid; + default: + state = sw_argument; } break; @@ -237,6 +255,18 @@ ngx_int_t ngx_imap_parse_command(ngx_ima state = sw_start_literal_argument; break; } + if (ch == '+') { + state = sw_no_sync_literal_argument; + break; + } + goto invalid; + + case sw_no_sync_literal_argument: + if (ch == '}') { + s->no_sync_literal = 1; + state = sw_start_literal_argument; + break; + } goto invalid; case sw_start_literal_argument: @@ -246,10 +276,17 @@ ngx_int_t ngx_imap_parse_command(ngx_ima case LF: s->buffer->pos = p + 1; s->arg_start = p + 1; - s->state = sw_literal_argument; - return NGX_IMAP_NEXT; + if (s->no_sync_literal == 0) { + s->state = sw_literal_argument; + return NGX_IMAP_NEXT; + } + state = sw_literal_argument; + s->no_sync_literal = 0; + break; + default: + goto invalid; } - goto invalid; + break; case sw_literal_argument: if (s->literal_len && --s->literal_len) { @@ -312,9 +349,11 @@ done: } arg->len = s->arg_end - s->arg_start; arg->data = s->arg_start; + s->arg_start = NULL; s->cmd_start = NULL; s->quoted = 0; + s->no_sync_literal = 0; s->literal_len = 0; } @@ -326,6 +365,7 @@ invalid: s->state = sw_start; s->quoted = 0; + s->no_sync_literal = 0; s->literal_len = 0; return NGX_IMAP_PARSE_INVALID_COMMAND; @@ -432,7 +472,14 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima case sw_argument: switch (ch) { - case ' ': + + /* + * the space should be considered part of the at username + * or password, but not of argument in other commands + * + * case ' ': + */ + case CR: case LF: arg = ngx_array_push(&s->args); diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c --- a/src/imap/ngx_imap_proxy_module.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -111,8 +111,8 @@ ngx_imap_proxy_init(ngx_imap_session_t * rc = ngx_event_connect_peer(&p->upstream); - if (rc == NGX_ERROR || rc == NGX_CONNECT_ERROR) { - ngx_imap_session_internal_server_error(s); + if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + ngx_imap_proxy_internal_server_error(s); return; } diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c --- a/src/imap/ngx_imap_ssl_module.c +++ b/src/imap/ngx_imap_ssl_module.c @@ -76,6 +76,9 @@ ngx_module_t ngx_imap_ssl_module = { }; +static u_char ngx_imap_session_id_ctx[] = "IMAP"; + + static void * ngx_imap_ssl_create_conf(ngx_conf_t *cf) { @@ -176,7 +179,16 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, return NGX_CONF_ERROR; } - SSL_CTX_set_verify(conf->ssl_ctx, SSL_VERIFY_NONE, NULL); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); + + SSL_CTX_set_mode(conf->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + SSL_CTX_set_read_ahead(conf->ssl_ctx, 1); + + SSL_CTX_set_session_cache_mode(conf->ssl_ctx, SSL_SESS_CACHE_SERVER); + + SSL_CTX_set_session_id_context(conf->ssl_ctx, ngx_imap_session_id_ctx, + sizeof(ngx_imap_session_id_ctx) - 1); return NGX_CONF_OK; } diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -9,8 +9,9 @@ #include -ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, - ngx_log_t *log) +ngx_int_t +ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, + ngx_log_t *log) { ssize_t n; ngx_err_t err; @@ -77,8 +78,8 @@ ngx_int_t ngx_write_channel(ngx_socket_t } -ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, - ngx_log_t *log) +ngx_int_t +ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, ngx_log_t *log) { ssize_t n; ngx_err_t err; @@ -178,31 +179,40 @@ ngx_int_t ngx_read_channel(ngx_socket_t } -ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, - ngx_int_t event, ngx_event_handler_pt handler) +ngx_int_t +ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, ngx_int_t event, + ngx_event_handler_pt handler) { ngx_event_t *ev, *rev, *wev; ngx_connection_t *c; - c = &cycle->connections[fd]; - rev = &cycle->read_events[fd]; - wev = &cycle->write_events[fd]; + c = ngx_get_connection(fd, cycle->log); + + if (c == NULL) { + return NGX_ERROR; + } + + rev = c->read; + wev = c->write; ngx_memzero(c, sizeof(ngx_connection_t)); + + c->read = rev; + c->write = wev; + c->fd = fd; + c->log = cycle->log; + + c->pool = cycle->pool; + ngx_memzero(rev, sizeof(ngx_event_t)); ngx_memzero(wev, sizeof(ngx_event_t)); - c->fd = fd; - c->pool = cycle->pool; - - c->read = rev; - c->write = wev; - - c->log = cycle->log; rev->log = cycle->log; wev->log = cycle->log; + rev->index = NGX_INVALID_INDEX; wev->index = NGX_INVALID_INDEX; + rev->data = c; wev->data = c; @@ -219,11 +229,13 @@ ngx_int_t ngx_add_channel_event(ngx_cycl if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { + ngx_free_connection(c); return NGX_ERROR; } } else { if (ngx_add_event(ev, event, 0) == NGX_ERROR) { + ngx_free_connection(c); return NGX_ERROR; } } @@ -232,7 +244,8 @@ ngx_int_t ngx_add_channel_event(ngx_cycl } -void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log) +void +ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log) { if (close(fd[0]) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "close() channel failed"); diff --git a/src/os/unix/ngx_channel.h b/src/os/unix/ngx_channel.h --- a/src/os/unix/ngx_channel.h +++ b/src/os/unix/ngx_channel.h @@ -22,11 +22,11 @@ typedef struct { ngx_int_t ngx_write_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, - ngx_log_t *log); + ngx_log_t *log); ngx_int_t ngx_read_channel(ngx_socket_t s, ngx_channel_t *ch, size_t size, - ngx_log_t *log); + ngx_log_t *log); ngx_int_t ngx_add_channel_event(ngx_cycle_t *cycle, ngx_fd_t fd, - ngx_int_t event, ngx_event_handler_pt handler); + ngx_int_t event, ngx_event_handler_pt handler); void ngx_close_channel(ngx_fd_t *fd, ngx_log_t *log); 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 @@ -33,6 +33,7 @@ typedef int ngx_err_t; #define NGX_ENOTCONN ENOTCONN #define NGX_ETIMEDOUT ETIMEDOUT #define NGX_ECONNREFUSED ECONNREFUSED +#define NGX_ENAMETOOLONG ENAMETOOLONG #define NGX_EHOSTUNREACH EHOSTUNREACH #define NGX_ENOSYS ENOSYS #define NGX_ECANCELED ECANCELED diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -94,7 +94,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "no more than %d processes can be spawned", NGX_MAX_PROCESSES); - return NGX_ERROR; + return NGX_INVALID_PID; } } @@ -107,7 +107,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "socketpair() failed while spawning \"%s\"", name); - return NGX_ERROR; + return NGX_INVALID_PID; } ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, @@ -120,7 +120,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng ngx_nonblocking_n " failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) { @@ -128,7 +128,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng ngx_nonblocking_n " failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } on = 1; @@ -136,14 +136,14 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "ioctl(FIOASYNC) failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "fcntl(F_SETOWN) failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { @@ -151,7 +151,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) { @@ -159,7 +159,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; } ngx_channel = ngx_processes[s].channel[1]; @@ -180,7 +180,7 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "fork() failed while spawning \"%s\"", name); ngx_close_channel(ngx_processes[s].channel, cycle->log); - return NGX_ERROR; + return NGX_INVALID_PID; case 0: ngx_pid = ngx_getpid(); diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -13,6 +13,8 @@ typedef pid_t ngx_pid_t; +#define NGX_INVALID_PID -1 + typedef void (*ngx_spawn_proc_pt) (ngx_cycle_t *cycle, void *data); typedef struct { diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -513,9 +513,10 @@ ngx_signal_worker_processes(ngx_cycle_t static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle) { - ngx_int_t i, n; - ngx_uint_t live; - ngx_channel_t ch; + ngx_int_t i, n; + ngx_uint_t live; + ngx_channel_t ch; + ngx_core_conf_t *ccf; ch.command = NGX_CMD_CLOSE_CHANNEL; ch.fd = -1; @@ -575,7 +576,7 @@ ngx_reap_childs(ngx_cycle_t *cycle) if (ngx_spawn_process(cycle, ngx_processes[i].proc, ngx_processes[i].data, ngx_processes[i].name, i) - == NGX_ERROR) + == NGX_INVALID_PID) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "can not respawn %s", ngx_processes[i].name); @@ -615,6 +616,20 @@ ngx_reap_childs(ngx_cycle_t *cycle) } if (ngx_processes[i].pid == ngx_new_binary) { + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_core_module); + + if (ngx_rename_file((char *) ccf->oldpid.data, + (char *) ccf->pid.data) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_rename_file_n " %s back to %s failed " + "after the new binary process \"%s\" exited", + ccf->oldpid.data, ccf->pid.data, ngx_argv[0]); + } + ngx_new_binary = 0; if (ngx_noaccepting) { ngx_restart = 1; @@ -795,6 +810,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc sigset_t set; ngx_int_t n; ngx_uint_t i; + struct rlimit rlmt; struct timeval tv; ngx_core_conf_t *ccf; ngx_listening_t *ls; @@ -818,6 +834,30 @@ ngx_worker_process_init(ngx_cycle_t *cyc } } + if (ccf->rlimit_nofile != NGX_CONF_UNSET) { + rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile; + rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; + + if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "setrlimit(RLIMIT_NOFILE, %i) failed", + ccf->rlimit_nofile); + } + } + +#ifdef RLIMIT_SIGPENDING + if (ccf->rlimit_sigpending != NGX_CONF_UNSET) { + rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending; + rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; + + if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "setrlimit(RLIMIT_SIGPENDING, %i) failed", + ccf->rlimit_sigpending); + } + } +#endif + if (setgid(ccf->group) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setgid(%d) failed", ccf->group); @@ -874,7 +914,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { - ls[i].remain = 0; + ls[i].previous = NULL; } for (i = 0; ngx_modules[i]; i++) { @@ -928,6 +968,7 @@ static void ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; + ngx_socket_t fd; ngx_channel_t ch; ngx_connection_t *c; @@ -945,12 +986,17 @@ ngx_channel_handler(ngx_event_t *ev) ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); if (n == NGX_ERROR) { - if (close(c->fd) == -1) { + + ngx_free_connection(c); + + fd = c->fd; + c->fd = (ngx_socket_t) -1; + + if (close(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "close() channel failed"); } - c->fd = -1; return; } @@ -1144,7 +1190,7 @@ ngx_garbage_collector_cycle(ngx_cycle_t ngx_worker_process_init(cycle, 0); - ev = &cycle->read_events[ngx_channel]; + ev = &cycle->read_events0[ngx_channel]; ngx_accept_mutex = NULL;