diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/nginx.c | 623 | ||||
-rw-r--r-- | src/core/nginx.h | 15 | ||||
-rw-r--r-- | src/core/ngx_conf_file.c | 7 | ||||
-rw-r--r-- | src/core/ngx_conf_file.h | 32 | ||||
-rw-r--r-- | src/core/ngx_config.h | 21 | ||||
-rw-r--r-- | src/core/ngx_connection.c | 275 | ||||
-rw-r--r-- | src/core/ngx_connection.h | 8 | ||||
-rw-r--r-- | src/core/ngx_core.h | 1 | ||||
-rw-r--r-- | src/core/ngx_cycle.c | 743 | ||||
-rw-r--r-- | src/core/ngx_cycle.h | 36 | ||||
-rw-r--r-- | src/core/ngx_log.c | 2 | ||||
-rw-r--r-- | src/core/ngx_log.h | 7 | ||||
-rw-r--r-- | src/core/ngx_times.c | 12 | ||||
-rw-r--r-- | src/core/ngx_times.h | 2 |
14 files changed, 1474 insertions, 310 deletions
diff --git a/src/core/nginx.c b/src/core/nginx.c index 4ae4d099e..a36aad00c 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -5,18 +5,15 @@ #include <nginx.h> -/* STUB */ -void stub_init(ngx_cycle_t *cycle); - - - -static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log); -static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log); -static void ngx_clean_old_cycles(ngx_event_t *ev); +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); +static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv); +static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle); typedef struct { + ngx_str_t user; int daemon; + int single; ngx_str_t pid; } ngx_core_conf_t; @@ -25,6 +22,13 @@ static ngx_str_t core_name = ngx_string("core"); static ngx_command_t ngx_core_commands[] = { + { ngx_string("user"), + NGX_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_core_str_slot, + 0, + offsetof(ngx_core_conf_t, user), + NULL }, + { ngx_string("daemon"), NGX_MAIN_CONF|NGX_CONF_TAKE1, ngx_conf_set_core_flag_slot, @@ -32,6 +36,13 @@ static ngx_command_t ngx_core_commands[] = { offsetof(ngx_core_conf_t, daemon), NULL }, + { ngx_string("single_process"), + NGX_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_core_flag_slot, + 0, + offsetof(ngx_core_conf_t, single), + NULL }, + ngx_null_command }; @@ -41,44 +52,46 @@ ngx_module_t ngx_core_module = { &core_name, /* module context */ ngx_core_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ - NULL, /* init module */ + ngx_core_module_init, /* init module */ NULL /* init child */ }; -int ngx_max_module; -ngx_os_io_t ngx_io; - -volatile ngx_cycle_t *ngx_cycle; -ngx_array_t ngx_old_cycles; - -static ngx_pool_t *ngx_temp_pool; -static ngx_event_t ngx_cleaner_event; +ngx_int_t ngx_max_module; -/* STUB NAME */ -static ngx_connection_t dumb; +/* STUB */ +uid_t user; u_int ngx_connection_counter; +ngx_int_t ngx_master; +ngx_int_t ngx_single; + -int done; -int restart; -int rotate; +ngx_int_t ngx_respawn; +ngx_int_t ngx_terminate; +ngx_int_t ngx_quit; +ngx_int_t ngx_reconfigure; +ngx_int_t ngx_reopen; +ngx_int_t ngx_change_binary; -int main(int argc, char *const *argv) +int main(int argc, char *const *argv, char **envp) { - int i; - ngx_fd_t fd; - ngx_log_t *log; - ngx_cycle_t *cycle, init_cycle; - ngx_open_file_t *file; + struct timeval tv; + ngx_fd_t fd; + ngx_int_t i; + ngx_err_t err; + ngx_log_t *log; + ngx_cycle_t *cycle, init_cycle; + ngx_open_file_t *file; + ngx_core_conf_t *ccf; #if !(WIN32) - size_t len; - char pid[/* STUB */ 10]; - ngx_file_t pidfile; - ngx_core_conf_t *ccf; + size_t len; + char pid[/* STUB */ 10]; + ngx_file_t pidfile; + struct passwd *pwd; #endif #if __FreeBSD__ @@ -94,7 +107,6 @@ int main(int argc, char *const *argv) log = ngx_log_init_errlog(); - /* init_cycle->log is required for signal handlers */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); @@ -110,16 +122,46 @@ int main(int argc, char *const *argv) ngx_modules[i]->index = ngx_max_module++; } - cycle = ngx_init_cycle(NULL, log); + if (!(init_cycle.pool = ngx_create_pool(1024, log))) { + return 1; + } + + if (ngx_set_inherited_sockets(&init_cycle, envp) == NGX_ERROR) { + return 1; + } + + cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { return 1; } ngx_cycle = cycle; + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + if (ccf->single == 1) { + ngx_master = 0; + ngx_single = 1; + + } else { + ngx_master = 1; + ngx_single = 0; + } + #if !(WIN32) - ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + /* STUB */ + if (ccf->user.len) { + pwd = getpwnam(ccf->user.data); + if (pwd == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "getpwnam(%s) failed", ccf->user); + return 1; + } + + user = pwd->pw_uid; + } + /* */ if (ccf->daemon != 0) { if (ngx_daemon(cycle->log) == NGX_ERROR) { @@ -162,48 +204,64 @@ int main(int argc, char *const *argv) #endif - /* life cycle */ + /* a life cycle */ for ( ;; ) { -#if 0 - /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG|NGX_LOG_DEBUG_HTTP; -#endif - -#if 0 + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "new cycle"); -#if !(WIN32) - ngx_spawn_process(cycle->log); -#endif - - stub_init(cycle); -#endif - - /* TODO: forks */ + if (ngx_master) { + ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL, + "worker process", NGX_PROCESS_RESPAWN); - ngx_init_temp_number(); + } else { + ngx_init_temp_number(); - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->init_child) { - if (ngx_modules[i]->init_child(cycle) == NGX_ERROR) { - /* fatal */ - exit(1); + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_process) { + if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); + } } } } - /* TODO: threads */ +#if 0 + reconfigure = 0; + reopen = 0; +#endif - restart = 0; - rotate = 0; + /* a cycle with the same configuration */ for ( ;; ) { + /* an event loop */ + for ( ;; ) { - ngx_log_debug(cycle->log, "worker cycle"); - ngx_process_events(cycle->log); + err = 0; + + if (ngx_single) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "worker cycle"); + + ngx_process_events(cycle->log); - if (done) { + } else { + ngx_set_errno(0); + ngx_msleep(1000); + err = ngx_errno; + + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); + + if (err) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, err, + "sleep() exited"); + } + } + + if (ngx_quit || ngx_terminate) { #if !(WIN32) if (ngx_delete_file(pidfile.name.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, @@ -212,90 +270,70 @@ int main(int argc, char *const *argv) } #endif - ngx_log_error(NGX_LOG_INFO, - cycle->log, 0, "exiting"); - exit(0); - } - - if (rotate) { - ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); - - file = cycle->open_files.elts; - for (i = 0; i < cycle->open_files.nelts; i++) { - if (file[i].name.data == NULL) { - continue; - } + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); - fd = ngx_open_file(file[i].name.data, - NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); + if (ngx_master) { + ngx_signal_processes(cycle, + ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); -ngx_log_debug(log, "REOPEN: %d:%d:%s" _ fd _ file[i].fd _ file[i].name.data); + /* TODO: wait workers */ - if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", - file[i].name.data); - continue; - } + ngx_msleep(1000); -#if (WIN32) - if (ngx_file_append_mode(fd) == NGX_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_file_append_mode_n - " \"%s\" failed", - file[i].name.data); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - file[i].name.data); - } - - continue; - } -#endif + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); + } - if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_EMERG, - cycle->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - file[i].name.data); - } + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exit"); + exit(0); + } - file[i].fd = fd; - } + if (err == NGX_EINTR) { + ngx_respawn_processes(cycle); + } - rotate = 0; + if (ngx_change_binary) { + ngx_change_binary = 0; + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "changing binary"); + ngx_exec_new_binary(cycle, argv); + /* TODO: quit workers */ } - if (restart) { - ngx_log_debug(cycle->log, "restart"); + if (ngx_reconfigure) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring"); break; } + if (ngx_reopen) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "reopening logs"); + ngx_reopen_files(cycle); + ngx_reopen = 0; + } + } - cycle = ngx_init_cycle(cycle, cycle->log); + cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; + ngx_reconfigure = 0; break; } } } +#if 0 -static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) +static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) { - int i, n, failed; + ngx_int_t i, n, failed; ngx_str_t conf_file; + ngx_log_t *log; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; @@ -304,6 +342,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) ngx_open_file_t *file; ngx_listening_t *ls, *nls; + log = old_cycle->log; if (!(pool = ngx_create_pool(16 * 1024, log))) { return NULL; @@ -318,7 +357,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) cycle->old_cycle = old_cycle; - n = old_cycle ? old_cycle->pathes.nelts : 10; + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) { ngx_destroy_pool(pool); return NULL; @@ -329,7 +368,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) cycle->pathes.pool = pool; - n = old_cycle ? old_cycle->open_files.nelts : 20; + n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20; cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t)); if (cycle->open_files.elts == NULL) { ngx_destroy_pool(pool); @@ -347,7 +386,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) } - n = old_cycle ? old_cycle->listening.nelts : 10; + n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); if (cycle->listening.elts == NULL) { ngx_destroy_pool(pool); @@ -375,6 +414,7 @@ static ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle, ngx_log_t *log) * ccf->pid = NULL; */ ccf->daemon = -1; + ccf->single = -1; ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf; @@ -435,12 +475,8 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); #endif } -#if 0 - /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG; -#endif - if (!failed) { - if (old_cycle) { + if (old_cycle->listening.nelts) { ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { ls[i].remain = 0; @@ -449,6 +485,15 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); nls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].ignore) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "%X, %X", + *(int *) ls[i].sockaddr, + *(int *) nls[n].sockaddr); + if (ngx_memcmp(nls[n].sockaddr, ls[i].sockaddr, ls[i].socklen) == 0) { @@ -492,7 +537,7 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); } if (!failed) { - if (ngx_open_listening_sockets(cycle, log) == NGX_ERROR) { + if (ngx_open_listening_sockets(cycle) == NGX_ERROR) { failed = 1; } } @@ -536,9 +581,6 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); pool->log = cycle->log; -#if 1 - /* STUB */ cycle->one_process = 1; -#endif for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_module) { @@ -549,9 +591,9 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); } } - if (old_cycle == NULL) { - return cycle; - } + /* close and delete stuff that lefts from an old cycle */ + + /* close the unneeded listening sockets */ ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { @@ -566,6 +608,9 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); } } + + /* close the unneeded open files */ + file = old_cycle->open_files.elts; for (i = 0; i < old_cycle->open_files.nelts; i++) { if (file[i].fd == NGX_INVALID_FILE) { @@ -579,8 +624,13 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); } } + if (old_cycle->connections == NULL) { + /* an old cycle is an init cycle */ + ngx_destroy_pool(old_cycle->pool); + return cycle; + } - if (!old_cycle->one_process) { + if (master) { ngx_destroy_pool(old_cycle->pool); return cycle; } @@ -626,190 +676,233 @@ ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); return cycle; } - -static int ngx_open_listening_sockets(ngx_cycle_t *cycle, ngx_log_t *log) -{ - int times, failed, reuseaddr, i; - ngx_err_t err; - ngx_socket_t s; - ngx_listening_t *ls; - - reuseaddr = 1; -#if (NGX_SUPPRESS_WARN) - failed = 0; #endif - /* TODO: times configurable */ - for (times = 10; times; times--) { - failed = 0; +#if 0 - /* for each listening socket */ +static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } - if (ls[i].fd != -1) { - continue; - } + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); - if (ls[i].inherited) { + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); - /* TODO: close on exit */ - /* TODO: nonblocking */ - /* TODO: deferred accept */ + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; - continue; - } + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } - s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, - ls[i].flags); + ls->fd = s; - if (s == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_socket_n " %s failed", ls[i].addr_text.data); - return NGX_ERROR; - } + /* AF_INET only */ -#if (WIN32) - /* - * Winsock assignes a socket number divisible by 4 - * so to find a connection we divide a socket number by 4. - */ - - if (s % 4) { - ngx_log_error(NGX_LOG_EMERG, ls->log, 0, - ngx_socket_n " created socket %d", s); - return NGX_ERROR; - } -#endif + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &reuseaddr, sizeof(int)) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEADDR) %s failed", - ls[i].addr_text.data); - return NGX_ERROR; - } + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } - /* TODO: close on exit */ + addr_in = (struct sockaddr_in *) ls->sockaddr; - if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { - if (ngx_nonblocking(s) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_nonblocking_n " %s failed", - ls[i].addr_text.data); + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; + + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { return NGX_ERROR; } - } -#if 0 - if (ls[i].nonblocking) { - if (ngx_nonblocking(s) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_nonblocking_n " %s failed", - ls[i].addr_text.data); + addr_in->sin_len = 0; + + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { return NGX_ERROR; } } + } + + break; + } + + return NGX_OK; +} + #endif - if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { - err = ngx_socket_errno; - ngx_log_error(NGX_LOG_EMERG, log, err, - "bind() to %s failed", ls[i].addr_text.data); - if (err != NGX_EADDRINUSE) - return NGX_ERROR; +static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) +{ + ngx_int_t i; + ngx_listening_t *ls; + + if (user) { + if (setuid(user) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "setuid() failed"); + /* fatal */ + exit(1); + } + } - if (ngx_close_socket(s) == -1) - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %s failed", - ls[i].addr_text.data); + ngx_init_temp_number(); - failed = 1; - continue; - } + /* + * disable deleting previous events for the listening sockets because + * in the worker processes there are no events at all at this point + */ + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].remain = 0; + } - if (listen(s, ls[i].backlog) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "listen() to %s failed", ls[i].addr_text.data); - return NGX_ERROR; + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_process) { + if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); } + } + } + + /* TODO: threads: start ngx_worker_thread_cycle() */ + + for ( ;; ) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); - /* TODO: deferred accept */ + ngx_process_events(cycle->log); - ls[i].fd = s; + if (ngx_terminate) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); + exit(0); } - if (!failed) + if (ngx_quit) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "gracefully shutdowning"); break; + } - /* TODO: delay configurable */ - - ngx_log_error(NGX_LOG_NOTICE, log, 0, - "try again to bind() after 500ms"); - ngx_msleep(500); + if (ngx_reopen) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); + ngx_reopen_files(cycle); + ngx_reopen = 0; + } } - if (failed) { - ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); - return NGX_ERROR; - } + ngx_close_listening_sockets(cycle); - return NGX_OK; + for ( ;; ) { + if (ngx_event_timer_rbtree == &ngx_event_timer_sentinel) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); + exit(0); + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + + ngx_process_events(cycle->log); + } } -static void ngx_clean_old_cycles(ngx_event_t *ev) +static void ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { - int i, n, found, live; - ngx_log_t *log; - ngx_cycle_t **cycle; + char *env[2], *var, *p; + ngx_int_t i; + ngx_exec_ctx_t ctx; + ngx_listening_t *ls; - log = ngx_cycle->log; - ngx_temp_pool->log = log; + ctx.path = argv[0]; + ctx.name = "new binary process"; + ctx.argv = argv; - ngx_log_debug(log, "clean old cycles"); + var = ngx_alloc(NGINX_VAR_LEN + + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 1, + cycle->log); - live = 0; + p = ngx_cpymem(var, NGINX_VAR, NGINX_VAR_LEN); - cycle = ngx_old_cycles.elts; - for (i = 0; i < ngx_old_cycles.nelts; i++) { + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + p += ngx_snprintf(p, NGX_INT32_LEN + 2, "%u;", ls[i].fd); + } - if (cycle[i] == NULL) { - continue; - } + env[0] = var; + env[1] = NULL; + ctx.envp = (char *const *) &env; - found = 0; + ngx_exec(cycle, &ctx); - for (n = 0; n < cycle[i]->connection_n; n++) { - if (cycle[i]->connections[n].fd != -1) { - found = 1; - ngx_log_debug(log, "live fd: %d" _ n); - break; - } - } + ngx_free(var); +} - if (found) { - live = 1; - continue; - } - ngx_log_debug(log, "clean old cycle: %d" _ i); - ngx_destroy_pool(cycle[i]->pool); - cycle[i] = NULL; - } +static ngx_int_t ngx_core_module_init(ngx_cycle_t *cycle) +{ + ngx_core_conf_t *ccf; - ngx_log_debug(log, "old cycles status: %d" _ live); + /* + * ngx_core_module has a special init procedure: it is called by + * ngx_init_cycle() before the configuration file parsing to create + * ngx_core_module configuration and to set its default parameters + */ - if (live) { - ngx_log_debug(log, "TIMER"); - ngx_add_timer(ev, 30000); + if (((void **)(cycle->conf_ctx))[ngx_core_module.index] != NULL) { + return NGX_OK; + } - } else { - ngx_destroy_pool(ngx_temp_pool); - ngx_temp_pool = NULL; - ngx_old_cycles.nelts = 0; + if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) { + return NGX_ERROR; } + /* set by pcalloc() + * + * ccf->pid = NULL; + */ + ccf->daemon = -1; + ccf->single = -1; + + ((void **)(cycle->conf_ctx))[ngx_core_module.index] = ccf; + + return NGX_OK; } diff --git a/src/core/nginx.h b/src/core/nginx.h index 38942aa25..238512f8e 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -2,16 +2,19 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.0.1" -#define NGINX_CONF "nginx.conf" -#define NGINX_PID "nginx.pid" +#define NGINX_VER "nginx/0.0.1" +#define NGINX_CONF "nginx.conf" +#define NGINX_PID "nginx.pid" +#define NGINX_VAR "NGINX=" +#define NGINX_VAR_LEN (sizeof(NGINX_VAR) - 1) -extern int ngx_max_module; -extern u_int ngx_connection_counter; +extern ngx_module_t ngx_core_module; -extern ngx_module_t ngx_core_module; +extern ngx_uint_t ngx_connection_counter; +extern ngx_int_t ngx_master; +extern ngx_int_t ngx_single; #endif /* _NGINX_H_INCLUDED_ */ diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c index 249239072..704365c6a 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -571,6 +571,13 @@ char *ngx_conf_set_core_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, } +char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + return ngx_conf_set_str_slot(cf, cmd, *(void **)conf); +} + + char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index 536294779..e1c4e33ce 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -85,26 +85,6 @@ struct ngx_open_file_s { }; -struct ngx_cycle_s { - void ****conf_ctx; - ngx_pool_t *pool; - ngx_log_t *log; - ngx_array_t listening; - ngx_array_t open_files; - ngx_array_t pathes; - - int connection_n; - ngx_connection_t *connections; - ngx_event_t *read_events; - ngx_event_t *write_events; - - ngx_cycle_t *cycle; - ngx_cycle_t *old_cycle; - - unsigned one_process:1; -}; - - struct ngx_module_s { int ctx_index; int index; @@ -112,7 +92,10 @@ struct ngx_module_s { ngx_command_t *commands; int type; int (*init_module)(ngx_cycle_t *cycle); - int (*init_child)(ngx_cycle_t *cycle); + int (*init_process)(ngx_cycle_t *cycle); +#if 0 + int (*init_thread)(ngx_cycle_t *cycle); +#endif }; @@ -271,11 +254,12 @@ char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); char *ngx_conf_set_core_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_conf_set_core_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); -extern ngx_module_t *ngx_modules[]; -extern volatile ngx_cycle_t *ngx_cycle; -extern ngx_array_t ngx_old_cycles; +extern ngx_int_t ngx_max_module; +extern ngx_module_t *ngx_modules[]; #endif /* _NGX_HTTP_CONF_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h index 4f6f23dd9..e0e29fba5 100644 --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -59,14 +59,16 @@ typedef u_int ngx_uint_t; #if !(WIN32) -#define ngx_signal_helper(n) SIG##n -#define ngx_signal_value(n) ngx_signal_helper(n) +#define ngx_signal_helper(n) SIG##n +#define ngx_signal_value(n) ngx_signal_helper(n) /* TODO: #ifndef */ -#define NGX_RESTART_SIGNAL HUP -#define NGX_ROTATE_SIGNAL USR1 -#define NGX_SHUTDOWN_SIGNAL TERM -#define NGX_INTERRUPT_SIGNAL INT +#define NGX_RECONFIGURE_SIGNAL HUP +#define NGX_REOPEN_SIGNAL USR1 +#define NGX_SHUTDOWN_SIGNAL QUIT +#define NGX_TERMINATE_SIGNAL TERM +#define NGX_INTERRUPT_SIGNAL INT +#define NGX_CHANGEBIN_SIGNAL USR2 #endif @@ -76,6 +78,13 @@ typedef u_int ngx_uint_t; #define NGX_INVALID_ARRAY_INDEX 0x80000000 +/* TODO: auto */ +#define NGX_INT32_LEN sizeof("-2147483648") - 1 +#define NGX_TIME_T_LEN sizeof("-2147483648") - 1 +#define NGX_OFF_T_LEN sizeof("-9223372036854775808") - 1 + + + /* TODO: auto_conf */ #define NGX_ALIGN (sizeof(unsigned long) - 1) /* platform word */ #define NGX_ALIGN_CAST (unsigned long) /* size of the pointer */ diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c new file mode 100644 index 000000000..5e228fd38 --- /dev/null +++ b/src/core/ngx_connection.c @@ -0,0 +1,275 @@ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +/* STUB */ +#include <nginx.h> + + +ngx_os_io_t ngx_io; + + +ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); + + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); + + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; + + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } + + ls->fd = s; + + /* AF_INET only */ + + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } + + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls->sockaddr; + + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; + + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { + return NGX_ERROR; + } + + addr_in->sin_len = 0; + + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { + return NGX_ERROR; + } + } + } + + break; + } + + return NGX_OK; +} + + +ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +{ + int tries, failed, reuseaddr, i; + ngx_err_t err; + ngx_log_t *log; + ngx_socket_t s; + ngx_listening_t *ls; + + reuseaddr = 1; +#if (NGX_SUPPRESS_WARN) + failed = 0; +#endif + + log = cycle->log; + + /* TODO: tries configurable */ + + for (tries = 10; tries; tries--) { + failed = 0; + + /* for each listening socket */ + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (ls[i].ignore) { + continue; + } + + if (ls[i].fd != -1) { + continue; + } + + if (ls[i].inherited) { + + /* TODO: close on exit */ + /* TODO: nonblocking */ + /* TODO: deferred accept */ + + continue; + } + + s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, + ls[i].flags); + + if (s == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + return NGX_ERROR; + } +#endif + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: close on exit */ + + if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } + +#if 0 + if (ls[i].nonblocking) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } +#endif + + if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_EMERG, log, err, + "bind() to %s failed", ls[i].addr_text.data); + + if (err != NGX_EADDRINUSE) + return NGX_ERROR; + + if (ngx_close_socket(s) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + + failed = 1; + continue; + } + + if (listen(s, ls[i].backlog) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "listen() to %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: deferred accept */ + + ls[i].fd = s; + } + + if (!failed) + break; + + /* TODO: delay configurable */ + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "try again to bind() after 500ms"); + ngx_msleep(500); + } + + if (failed) { + ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +void ngx_close_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_int_t i; + ngx_socket_t fd; + ngx_listening_t *ls; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + return; + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + fd = ls[i].fd; + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + + ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT); + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + + cycle->connections[fd].fd = -1; + } +} diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index adb47911f..251b5c504 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -36,6 +36,7 @@ typedef struct { unsigned new:1; unsigned remain:1; + unsigned ignore:1; unsigned bound:1; /* already bound */ unsigned inherited:1; /* inherited from previous process */ @@ -85,13 +86,18 @@ struct ngx_connection_s { unsigned pipeline:1; unsigned unexpected_eof:1; - unsigned tcp_nopush:1; + signed tcp_nopush:2; #if (HAVE_IOCP) unsigned accept_context_updated:1; #endif }; +ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp); +ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); +void ngx_close_listening_sockets(ngx_cycle_t *cycle); + + extern ngx_os_io_t ngx_io; diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h index 75658bacb..6bfefcc49 100644 --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -37,6 +37,7 @@ typedef struct ngx_connection_s ngx_connection_t; #include <ngx_rbtree.h> #include <ngx_times.h> #include <ngx_inet.h> +#include <ngx_cycle.h> #include <ngx_conf_file.h> #include <ngx_os.h> #include <ngx_connection.h> diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c new file mode 100644 index 000000000..29af02253 --- /dev/null +++ b/src/core/ngx_cycle.c @@ -0,0 +1,743 @@ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +/* STUB */ +#include <nginx.h> + + +static void ngx_clean_old_cycles(ngx_event_t *ev); + + +volatile ngx_cycle_t *ngx_cycle; +ngx_array_t ngx_old_cycles; + +static ngx_pool_t *ngx_temp_pool; +static ngx_event_t ngx_cleaner_event; + + +/* STUB NAME */ +static ngx_connection_t dumb; +/* STUB */ + + +ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) +{ + ngx_int_t i, n, failed; + ngx_str_t conf_file; + ngx_log_t *log; + ngx_conf_t conf; + ngx_pool_t *pool; + ngx_cycle_t *cycle, **old; + ngx_socket_t fd; + ngx_open_file_t *file; + ngx_listening_t *ls, *nls; + + log = old_cycle->log; + + if (!(pool = ngx_create_pool(16 * 1024, log))) { + return NULL; + } + + if (!(cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)))) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->pool = pool; + + cycle->old_cycle = old_cycle; + + + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; + if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->pathes.nelts = 0; + cycle->pathes.size = sizeof(ngx_path_t *); + cycle->pathes.nalloc = n; + cycle->pathes.pool = pool; + + + n = old_cycle->open_files.nelts ? old_cycle->open_files.nelts : 20; + cycle->open_files.elts = ngx_pcalloc(pool, n * sizeof(ngx_open_file_t)); + if (cycle->open_files.elts == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->open_files.nelts = 0; + cycle->open_files.size = sizeof(ngx_open_file_t); + cycle->open_files.nalloc = n; + cycle->open_files.pool = pool; + + + if (!(cycle->log = ngx_log_create_errlog(cycle, NULL))) { + ngx_destroy_pool(pool); + return NULL; + } + + + n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; + cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); + if (cycle->listening.elts == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + cycle->listening.nelts = 0; + cycle->listening.size = sizeof(ngx_listening_t); + cycle->listening.nalloc = n; + cycle->listening.pool = pool; + + + cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); + if (cycle->conf_ctx == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + + if (ngx_core_module.init_module(cycle) == NGX_ERROR) { + ngx_destroy_pool(pool); + return NULL; + } + + + ngx_memzero(&conf, sizeof(ngx_conf_t)); + /* STUB: init array ? */ + conf.args = ngx_create_array(pool, 10, sizeof(ngx_str_t)); + if (conf.args == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + + conf.ctx = cycle->conf_ctx; + conf.cycle = cycle; + /* STUB */ conf.pool = cycle->pool; + conf.log = log; + conf.module_type = NGX_CORE_MODULE; + conf.cmd_type = NGX_MAIN_CONF; + + conf_file.len = sizeof(NGINX_CONF) - 1; + conf_file.data = NGINX_CONF; + + if (ngx_conf_parse(&conf, &conf_file) != NGX_CONF_OK) { + ngx_destroy_pool(pool); + return NULL; + } + + + failed = 0; + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].name.data == NULL) { + continue; + } + + file[i].fd = ngx_open_file(file[i].name.data, + NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); + +ngx_log_debug(log, "OPEN: %d:%s" _ file[i].fd _ file[i].name.data); + + if (file[i].fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_open_file_n " \"%s\" failed", + file[i].name.data); + failed = 1; + break; + } + +#if (WIN32) + if (ngx_file_append_mode(file[i].fd) == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_file_append_mode_n " \"%s\" failed", + file[i].name.data); + failed = 1; + break; + } +#endif + } + + if (!failed) { + if (old_cycle->listening.nelts) { + ls = old_cycle->listening.elts; + for (i = 0; i < old_cycle->listening.nelts; i++) { + ls[i].remain = 0; + } + + nls = cycle->listening.elts; + for (n = 0; n < cycle->listening.nelts; n++) { + for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].ignore) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, log, 0, + "%X, %X", + *(int *) ls[i].sockaddr, + *(int *) nls[n].sockaddr); + + if (ngx_memcmp(nls[n].sockaddr, + ls[i].sockaddr, ls[i].socklen) == 0) + { + fd = ls[i].fd; +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 so + * to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + if (fd >= (ngx_socket_t) cycle->connection_n) { + ngx_log_error(NGX_LOG_EMERG, log, 0, + "%d connections is not enough to hold " + "an open listening socket on %s, " + "required at least %d connections", + cycle->connection_n, + ls[i].addr_text.data, fd); + failed = 1; + break; + } + + nls[n].fd = ls[i].fd; + nls[i].remain = 1; + ls[i].remain = 1; + break; + } + } + + if (nls[n].fd == -1) { + nls[n].new = 1; + } + } + + } else { + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + ls[i].new = 1; + } + } + + if (!failed) { + if (ngx_open_listening_sockets(cycle) == NGX_ERROR) { + failed = 1; + } + } + } + + if (failed) { + + /* rollback the new cycle configuration */ + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].fd == NGX_INVALID_FILE) { + continue; + } + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + if (ls[i].new && ls[i].fd == -1) { + continue; + } + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + } + + ngx_destroy_pool(pool); + return NULL; + } + + /* commit the new cycle configuration */ + + pool->log = cycle->log; + + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->init_module) { + if (ngx_modules[i]->init_module(cycle) == NGX_ERROR) { + /* fatal */ + exit(1); + } + } + } + + /* close and delete stuff that lefts from an old cycle */ + + /* close the unneeded listening sockets */ + + ls = old_cycle->listening.elts; + for (i = 0; i < old_cycle->listening.nelts; i++) { + if (ls[i].remain) { + continue; + } + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + } + + + /* close the unneeded open files */ + + file = old_cycle->open_files.elts; + for (i = 0; i < old_cycle->open_files.nelts; i++) { + if (file[i].fd == NGX_INVALID_FILE) { + continue; + } + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + } + + if (old_cycle->connections == NULL) { + /* an old cycle is an init cycle */ + ngx_destroy_pool(old_cycle->pool); + return cycle; + } + + if (ngx_master) { + ngx_destroy_pool(old_cycle->pool); + return cycle; + } + + if (ngx_temp_pool == NULL) { + ngx_temp_pool = ngx_create_pool(128, cycle->log); + if (ngx_temp_pool == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "can not create ngx_temp_pool"); + exit(1); + } + + n = 10; + ngx_old_cycles.elts = ngx_pcalloc(ngx_temp_pool, + n * sizeof(ngx_cycle_t *)); + if (ngx_old_cycles.elts == NULL) { + exit(1); + } + ngx_old_cycles.nelts = 0; + ngx_old_cycles.size = sizeof(ngx_cycle_t *); + ngx_old_cycles.nalloc = n; + ngx_old_cycles.pool = ngx_temp_pool; + + ngx_cleaner_event.event_handler = ngx_clean_old_cycles; + ngx_cleaner_event.log = cycle->log; + ngx_cleaner_event.data = &dumb; + dumb.fd = (ngx_socket_t) -1; + } + + ngx_temp_pool->log = cycle->log; + + old = ngx_push_array(&ngx_old_cycles); + if (old == NULL) { + exit(1); + } + *old = old_cycle; + + if (!ngx_cleaner_event.timer_set) { + ngx_add_timer(&ngx_cleaner_event, 30000); + ngx_cleaner_event.timer_set = 1; + } + + return cycle; +} + + +#if 0 + + +static ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle, char **envp) +{ + char *p, *v; + ngx_socket_t s; + ngx_listening_t *ls; + struct sockaddr_in *addr_in; + + for ( /* void */ ; *envp; envp++) { + if (ngx_strncmp(*envp, NGINX_VAR, NGINX_VAR_LEN) != 0) { + continue; + } + + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "using inherited sockets from \"%s\"", *envp); + + ngx_init_array(cycle->listening, cycle->pool, + 10, sizeof(ngx_listening_t), NGX_ERROR); + + for (p = *envp + NGINX_VAR_LEN, v = p; *p; p++) { + if (*p == ':' || *p == ';') { + s = ngx_atoi(v, p - v); + if (s == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid socket number \"%s\" " + "in NGINX enviroment variable, " + "ignoring the rest of the variable", v); + break; + } + v = p + 1; + + if (!(ls = ngx_push_array(&cycle->listening))) { + return NGX_ERROR; + } + + ls->fd = s; + + /* AF_INET only */ + + ls->sockaddr = ngx_palloc(cycle->pool, + sizeof(struct sockaddr_in)); + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } + + ls->socklen = sizeof(struct sockaddr_in); + if (getsockname(s, ls->sockaddr, &ls->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "getsockname() of the inherited " + "socket #%d failed", s); + ls->ignore = 1; + continue; + } + + addr_in = (struct sockaddr_in *) ls->sockaddr; + + if (addr_in->sin_family != AF_INET) { + ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, + "the inherited socket #%d has " + "unsupported family", s); + ls->ignore = 1; + continue; + } + ls->addr_text_max_len = INET_ADDRSTRLEN; + + ls->addr_text.data = ngx_palloc(cycle->pool, + ls->addr_text_max_len); + if (ls->addr_text.data == NULL) { + return NGX_ERROR; + } + + addr_in->sin_len = 0; + + ls->family = addr_in->sin_family; + ls->addr_text.len = ngx_sock_ntop(ls->family, ls->sockaddr, + ls->addr_text.data, + ls->addr_text_max_len); + if (ls->addr_text.len == 0) { + return NGX_ERROR; + } + } + } + + break; + } + + return NGX_OK; +} + + +static ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +{ + int tries, failed, reuseaddr, i; + ngx_err_t err; + ngx_log_t *log; + ngx_socket_t s; + ngx_listening_t *ls; + + reuseaddr = 1; +#if (NGX_SUPPRESS_WARN) + failed = 0; +#endif + + log = cycle->log; + + /* TODO: tries configurable */ + + for (tries = 10; tries; tries--) { + failed = 0; + + /* for each listening socket */ + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (ls[i].ignore) { + continue; + } + + if (ls[i].fd != -1) { + continue; + } + + if (ls[i].inherited) { + + /* TODO: close on exit */ + /* TODO: nonblocking */ + /* TODO: deferred accept */ + + continue; + } + + s = ngx_socket(ls[i].family, ls[i].type, ls[i].protocol, + ls[i].flags); + + if (s == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_socket_n " %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + if (s % 4) { + ngx_log_error(NGX_LOG_EMERG, ls->log, 0, + ngx_socket_n " created socket %d", s); + return NGX_ERROR; + } +#endif + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: close on exit */ + + if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } + +#if 0 + if (ls[i].nonblocking) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_nonblocking_n " %s failed", + ls[i].addr_text.data); + return NGX_ERROR; + } + } +#endif + + if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) { + err = ngx_socket_errno; + ngx_log_error(NGX_LOG_EMERG, log, err, + "bind() to %s failed", ls[i].addr_text.data); + + if (err != NGX_EADDRINUSE) + return NGX_ERROR; + + if (ngx_close_socket(s) == -1) + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + + failed = 1; + continue; + } + + if (listen(s, ls[i].backlog) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + "listen() to %s failed", ls[i].addr_text.data); + return NGX_ERROR; + } + + /* TODO: deferred accept */ + + ls[i].fd = s; + } + + if (!failed) + break; + + /* TODO: delay configurable */ + + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "try again to bind() after 500ms"); + ngx_msleep(500); + } + + if (failed) { + ngx_log_error(NGX_LOG_EMERG, log, 0, "still can not bind()"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +#endif + + +void ngx_reopen_files(ngx_cycle_t *cycle) +{ + ngx_fd_t fd; + ngx_int_t i; + ngx_open_file_t *file; + + file = cycle->open_files.elts; + for (i = 0; i < cycle->open_files.nelts; i++) { + if (file[i].name.data == NULL) { + continue; + } + + fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND); + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "reopen file \"%s\", old:%d new:%d", + file[i].name.data, file[i].fd, fd); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", file[i].name.data); + continue; + } + +#if (WIN32) + if (ngx_file_append_mode(fd) == NGX_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_file_append_mode_n " \"%s\" failed", + file[i].name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + + continue; + } +#endif + + if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + file[i].name.data); + } + + file[i].fd = fd; + } +} + + +#if 0 + +static void ngx_close_listening_sockets(ngx_cycle_t *cycle) +{ + ngx_int_t i; + ngx_socket_t fd; + ngx_listening_t *ls; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + return; + } + + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + fd = ls[i].fd; + +#if (WIN32) + /* + * Winsock assignes a socket number divisible by 4 + * so to find a connection we divide a socket number by 4. + */ + + fd /= 4; +#endif + + ngx_del_event(&cycle->read_events[fd], NGX_READ_EVENT, NGX_CLOSE_EVENT); + + if (ngx_close_socket(ls[i].fd) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " %s failed", + ls[i].addr_text.data); + } + + cycle->connections[fd].fd = -1; + } +} + +#endif + + +static void ngx_clean_old_cycles(ngx_event_t *ev) +{ + int i, n, found, live; + ngx_log_t *log; + ngx_cycle_t **cycle; + + log = ngx_cycle->log; + ngx_temp_pool->log = log; + + ngx_log_debug(log, "clean old cycles"); + + live = 0; + + cycle = ngx_old_cycles.elts; + for (i = 0; i < ngx_old_cycles.nelts; i++) { + + if (cycle[i] == NULL) { + continue; + } + + found = 0; + + for (n = 0; n < cycle[i]->connection_n; n++) { + if (cycle[i]->connections[n].fd != -1) { + found = 1; + ngx_log_debug(log, "live fd: %d" _ n); + break; + } + } + + if (found) { + live = 1; + continue; + } + + ngx_log_debug(log, "clean old cycle: %d" _ i); + ngx_destroy_pool(cycle[i]->pool); + cycle[i] = NULL; + } + + ngx_log_debug(log, "old cycles status: %d" _ live); + + if (live) { + ngx_log_debug(log, "TIMER"); + ngx_add_timer(ev, 30000); + + } else { + ngx_destroy_pool(ngx_temp_pool); + ngx_temp_pool = NULL; + ngx_old_cycles.nelts = 0; + } +} diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h new file mode 100644 index 000000000..376a44d34 --- /dev/null +++ b/src/core/ngx_cycle.h @@ -0,0 +1,36 @@ +#ifndef _NGX_CYCLE_H_INCLUDED_ +#define _NGX_CYCLE_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> + + +struct ngx_cycle_s { + void ****conf_ctx; + ngx_pool_t *pool; + ngx_log_t *log; + ngx_array_t listening; + ngx_array_t open_files; + ngx_array_t pathes; + + int connection_n; + ngx_connection_t *connections; + ngx_event_t *read_events; + ngx_event_t *write_events; + + ngx_cycle_t *old_cycle; + + unsigned one_process:1; +}; + + +ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle); +void ngx_reopen_files(ngx_cycle_t *cycle); + + +extern volatile ngx_cycle_t *ngx_cycle; +extern ngx_array_t ngx_old_cycles; + + +#endif /* _NGX_CYCLE_H_INCLUDED_ */ diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c index 98b71c8d3..de238f526 100644 --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -52,7 +52,7 @@ static const char *err_levels[] = { }; static const char *debug_levels[] = { - "debug", "debug_alloc", "debug_event", "debug_http" + "debug", "debug_core", "debug_alloc", "debug_event", "debug_http" }; diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h index 2d7f2e94f..ab96a463d 100644 --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -16,9 +16,10 @@ #define NGX_LOG_INFO 7 #define NGX_LOG_DEBUG 8 -#define NGX_LOG_DEBUG_ALLOC 0x10 -#define NGX_LOG_DEBUG_EVENT 0x20 -#define NGX_LOG_DEBUG_HTTP 0x40 +#define NGX_LOG_DEBUG_CORE 0x10 +#define NGX_LOG_DEBUG_ALLOC 0x20 +#define NGX_LOG_DEBUG_EVENT 0x40 +#define NGX_LOG_DEBUG_HTTP 0x80 #define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG #define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_HTTP diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index bc0cb1684..8a319c76f 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -39,19 +39,25 @@ void ngx_time_init() ngx_cached_http_log_time.data = cached_http_log_time; ngx_gettimeofday(&tv); - ngx_cached_time = tv.tv_sec; + ngx_cached_time = 0; ngx_start_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000; ngx_old_elapsed_msec = 0; ngx_elapsed_msec = 0; - ngx_time_update(); + ngx_time_update(tv.tv_sec); } -void ngx_time_update() +void ngx_time_update(time_t s) { ngx_tm_t tm; + if (ngx_cached_time == s) { + return; + } + + ngx_cached_time = s; + ngx_gmtime(ngx_cached_time, &ngx_cached_gmtime); ngx_cached_http_time.len = ngx_snprintf(ngx_cached_http_time.data, diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h index 98382b6ac..296004220 100644 --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -7,7 +7,7 @@ void ngx_time_init(); -void ngx_time_update(); +void ngx_time_update(time_t s); size_t ngx_http_time(char *buf, time_t t); void ngx_gmtime(time_t t, ngx_tm_t *tp); |