static ngx_int_t ngx_http_session_sticky_insert(ngx_http_request_t *r) { u_char *p; ngx_uint_t i; ngx_list_part_t *part; ngx_table_elt_t *set_cookie, *table; ngx_http_ss_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_upstream_session_sticky_module); if (ctx->frist != 1 && ctx->sscf->maxidle == NGX_CONF_UNSET) { return NGX_OK; } set_cookie = NULL; if (ctx->sscf->flag & NGX_HTTP_SESSION_STICKY_INDIRECT) { part = &r->headers_out.headers.part; while (part && set_cookie == NULL) { table = (ngx_table_elt_t *) part->elts; for (i = 0; i < part->nelts; i++) { if (table[i].key.len == (sizeof("set-cookie") - 1) && ngx_strncasecmp(table[i].key.data, (u_char *) "set-cookie", table[i].key.len) == 0) { p = ngx_strlcasestrn(table[i].value.data, table[i].value.data + table[i].value.len, ctx->sscf->cookie.data, ctx->sscf->cookie.len - 1); if (p != NULL) { set_cookie = &table[i]; break; } } } part = part->next; } } if (set_cookie == NULL) { set_cookie = ngx_list_push(&r->headers_out.headers); if (set_cookie == NULL) { return NGX_ERROR; } set_cookie->hash = 1; ngx_str_set(&set_cookie->key, "Set-Cookie"); } set_cookie->value.len = ctx->sscf->cookie.len + sizeof("=") - 1 + ctx->sid.len + sizeof(";Domain=") - 1 + ctx->sscf->domain.len + sizeof(";Path=") - 1 + ctx->sscf->path.len; if (ctx->sscf->maxidle != NGX_CONF_UNSET) { set_cookie->value.len = set_cookie->value.len + ctx->s_lastseen.len + ctx->s_firstseen.len + 2; /* '|' and '|' */ } else { set_cookie->value.len = set_cookie->value.len + sizeof(";Max-Age=") - 1 + ctx->sscf->maxage.len; } p = ngx_pnalloc(r->pool, set_cookie->value.len); if (p == NULL) { return NGX_ERROR; } set_cookie->value.data = p; p = ngx_cpymem(p, ctx->sscf->cookie.data, ctx->sscf->cookie.len); *p++ = '='; p = ngx_cpymem(p, ctx->sid.data, ctx->sid.len); if (ctx->sscf->maxidle != NGX_CONF_UNSET) { *(p++) = NGX_HTTP_SESSION_STICKY_DELIMITER; p = ngx_cpymem(p, ctx->s_lastseen.data, ctx->s_lastseen.len); *(p++) = NGX_HTTP_SESSION_STICKY_DELIMITER; p = ngx_cpymem(p, ctx->s_firstseen.data, ctx->s_firstseen.len); } if (ctx->sscf->domain.len) { p = ngx_cpymem(p, ";Domain=", sizeof(";Domain=") - 1); p = ngx_cpymem(p, ctx->sscf->domain.data, ctx->sscf->domain.len); } if (ctx->sscf->path.len) { p = ngx_cpymem(p, ";Path=", sizeof(";Path=") - 1); p = ngx_cpymem(p, ctx->sscf->path.data, ctx->sscf->path.len); } if (ctx->sscf->maxidle == NGX_CONF_UNSET && ctx->sscf->maxage.len) { p = ngx_cpymem(p, ";Max-Age=", sizeof(";Max-Age=") - 1); p = ngx_cpymem(p, ctx->sscf->maxage.data, ctx->sscf->maxage.len); } set_cookie->value.len = p - set_cookie->value.data; return NGX_OK; }
static ngx_int_t ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, ngx_http_lua_block_parser_ctx_t *ctx) { enum { OVEC_SIZE = 2 }; int i, rc; int ovec[OVEC_SIZE]; u_char *start, *p, *q, ch; off_t file_size; size_t len, buf_size; ssize_t n, size; ngx_uint_t start_line; ngx_str_t *word; ngx_buf_t *b; #if nginx_version >= 1009002 ngx_buf_t *dump; #endif b = cf->conf_file->buffer; #if nginx_version >= 1009002 dump = cf->conf_file->dump; #endif start = b->pos; start_line = cf->conf_file->line; buf_size = b->end - b->start; dd("lexer start line: %d", (int) start_line); file_size = ngx_file_size(&cf->conf_file->file.info); for ( ;; ) { if (b->pos >= b->last || (b->last - b->pos < (b->end - b->start) / 3 && cf->conf_file->file.offset < file_size)) { if (cf->conf_file->file.offset >= file_size) { cf->conf_file->line = ctx->start_line; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting " "terminating characters for lua code " "block"); return NGX_ERROR; } len = b->last - start; if (len == buf_size) { cf->conf_file->line = start_line; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long lua code block, probably " "missing terminating characters"); return NGX_ERROR; } if (len) { ngx_memmove(b->start, start, len); } size = (ssize_t) (file_size - cf->conf_file->file.offset); if (size > b->end - (b->start + len)) { size = b->end - (b->start + len); } n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } if (n != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_read_file_n " returned " "only %z bytes instead of %z", n, size); return NGX_ERROR; } b->pos = b->start + (b->pos - start); b->last = b->start + len + n; start = b->start; #if nginx_version >= 1009002 if (dump) { dump->last = ngx_cpymem(dump->last, b->start + len, size); } #endif } rc = ngx_http_lua_lex(b->pos, b->last - b->pos, ovec); if (rc < 0) { /* no match */ /* alas. the lexer does not yet support streaming processing. need * more work below */ if (cf->conf_file->file.offset >= file_size) { cf->conf_file->line = ctx->start_line; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting " "terminating characters for lua code " "block"); return NGX_ERROR; } len = b->last - b->pos; if (len == buf_size) { cf->conf_file->line = start_line; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long lua code block, probably " "missing terminating characters"); return NGX_ERROR; } if (len) { ngx_memcpy(b->start, b->pos, len); } size = (ssize_t) (file_size - cf->conf_file->file.offset); if (size > b->end - (b->start + len)) { size = b->end - (b->start + len); } n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } if (n != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_read_file_n " returned " "only %z bytes instead of %z", n, size); return NGX_ERROR; } b->pos = b->start + len; b->last = b->pos + n; start = b->start; continue; } if (rc == FOUND_LEFT_LBRACKET_STR || rc == FOUND_LEFT_LBRACKET_CMT) { /* we update the line numbers for best error messages when the * closing long bracket is missing */ for (i = 0; i < ovec[0]; i++) { ch = b->pos[i]; if (ch == LF) { cf->conf_file->line++; } } b->pos += ovec[0]; ovec[1] -= ovec[0]; ovec[0] = 0; if (rc == FOUND_LEFT_LBRACKET_CMT) { p = &b->pos[2]; /* we skip the leading "--" prefix */ rc = FOUND_LBRACKET_CMT; } else { p = b->pos; rc = FOUND_LBRACKET_STR; } /* we temporarily rewrite [=*[ in the input buffer to ]=*] to * construct the pattern for the corresponding closing long * bracket without additional buffers. */ ngx_http_lua_assert(p[0] == '['); p[0] = ']'; ngx_http_lua_assert(b->pos[ovec[1] - 1] == '['); b->pos[ovec[1] - 1] = ']'; /* search for the corresponding closing bracket */ dd("search pattern for the closing long bracket: \"%.*s\" (len=%d)", (int) (b->pos + ovec[1] - p), p, (int) (b->pos + ovec[1] - p)); q = ngx_http_lua_strlstrn(b->pos + ovec[1], b->last, p, b->pos + ovec[1] - p - 1); if (q == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "Lua code block missing the closing " "long bracket \"%*s\"", b->pos + ovec[1] - p, p); return NGX_ERROR; } /* restore the original opening long bracket */ p[0] = '['; b->pos[ovec[1] - 1] = '['; ovec[1] = q - b->pos + b->pos + ovec[1] - p; dd("found long bracket token: \"%.*s\"", (int) (ovec[1] - ovec[0]), b->pos + ovec[0]); } for (i = 0; i < ovec[1]; i++) { ch = b->pos[i]; if (ch == LF) { cf->conf_file->line++; } } b->pos += ovec[1]; ctx->token_len = ovec[1] - ovec[0]; break; } word = ngx_array_push(cf->args); if (word == NULL) { return NGX_ERROR; } word->data = ngx_pnalloc(cf->temp_pool, b->pos - start); if (word->data == NULL) { return NGX_ERROR; } len = b->pos - start; ngx_memcpy(word->data, start, len); word->len = len; return rc; }
void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); size = sizeof(master_process); for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } title = ngx_pnalloc(cycle->pool, size); p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } ngx_setproctitle(title); ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_start_session_manager_processes(cycle, 0); ngx_start_ip_blacklist_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; sigio = 0; live = 1; for ( ;; ) { if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); sigsuspend(&set); ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); live = ngx_reap_children(cycle); } if (!live && (ngx_terminate || ngx_quit)) { ngx_master_process_exit(cycle); } if (ngx_terminate) { if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); } else { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; } if (ngx_quit) { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } if (ngx_reconfigure) { ngx_reconfigure = 0; if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_start_session_manager_processes(cycle, 0); ngx_start_ip_blacklist_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); ngx_start_session_manager_processes(cycle, 1); ngx_start_ip_blacklist_manager_processes(cycle, 1); /* allow new processes to start */ ngx_msleep(100); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_start_session_manager_processes(cycle, 0); ngx_start_ip_blacklist_manager_processes(cycle, 0); live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv, ngx_str_t *value, ngx_table_elt_t **output_header, unsigned no_create) { ngx_table_elt_t *h; ngx_list_part_t *part; ngx_uint_t i; unsigned matched = 0; if (hv->no_override) { goto new_header; } #if 1 if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') { /* XXX ngx_http_core_find_config_phase, for example, * may not initialize the "key" and "hash" fields * for a nasty optimization purpose, and * we have to work-around it here */ r->headers_out.location->hash = ngx_http_lua_location_hash; ngx_str_set(&r->headers_out.location->key, "Location"); } #endif part = &r->headers_out.headers.part; h = part->elts; for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; h = part->elts; i = 0; } if (h[i].hash != 0 && h[i].key.len == hv->key.len && ngx_strncasecmp(hv->key.data, h[i].key.data, h[i].key.len) == 0) { dd("found out header %.*s", (int) h[i].key.len, h[i].key.data); if (value->len == 0 || matched) { dd("clearing normal header for %.*s", (int) hv->key.len, hv->key.data); h[i].value.len = 0; h[i].hash = 0; } else { dd("setting header to value %.*s", (int) value->len, value->data); h[i].value = *value; h[i].hash = hv->hash; } if (output_header) { *output_header = &h[i]; } /* return NGX_OK; */ matched = 1; } } if (matched){ return NGX_OK; } if (no_create && value->len == 0) { return NGX_OK; } new_header: /* XXX we still need to create header slot even if the value * is empty because some builtin headers like Last-Modified * relies on this to get cleared */ h = ngx_list_push(&r->headers_out.headers); if (h == NULL) { return NGX_ERROR; } if (value->len == 0) { h->hash = 0; } else { h->hash = hv->hash; } h->key = hv->key; h->value = *value; h->lowcase_key = ngx_pnalloc(r->pool, h->key.len); if (h->lowcase_key == NULL) { return NGX_ERROR; } ngx_strlow(h->lowcase_key, h->key.data, h->key.len); if (output_header) { *output_header = h; } return NGX_OK; }
static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv) { SV *sv; int n, status; char *line; u_char *err; STRLEN len, n_a; ngx_uint_t i; ngx_connection_t *c; dSP; status = 0; ENTER; SAVETMPS; PUSHMARK(sp); sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); XPUSHs(sv); if (args) { EXTEND(sp, (intptr_t) args[0]); for (i = 1; i <= (ngx_uint_t) args[0]; i++) { PUSHs(sv_2mortal(args[i])); } } PUTBACK; c = r->connection; n = call_sv(sub, G_EVAL); SPAGAIN; if (n) { if (rv == NULL) { status = POPi; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "call_sv: %d", status); } else { line = SvPVx(POPs, n_a); rv->len = n_a; rv->data = ngx_pnalloc(r->pool, n_a); if (rv->data == NULL) { return NGX_ERROR; } ngx_memcpy(rv->data, line, n_a); } } PUTBACK; FREETMPS; LEAVE; /* check $@ */ if (SvTRUE(ERRSV)) { err = (u_char *) SvPV(ERRSV, len); while (--len && (err[len] == CR || err[len] == LF)) { /* void */ } ngx_log_error(NGX_LOG_ERR, c->log, 0, "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err); if (rv) { return NGX_ERROR; } return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (n != 1) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "call_sv(\"%V\") returned %d results", handler, n); status = NGX_OK; } if (rv) { return NGX_OK; } return (ngx_int_t) status; }
ngx_int_t ngx_postgres_upstream_get_peer(ngx_peer_connection_t *pc, void *data) { ngx_postgres_upstream_peer_data_t *pgdt = data; ngx_postgres_upstream_srv_conf_t *pgscf; #if defined(nginx_version) && (nginx_version < 8017) ngx_postgres_ctx_t *pgctx; #endif ngx_postgres_upstream_peers_t *peers; ngx_postgres_upstream_peer_t *peer; ngx_connection_t *pgxc = NULL; int fd; ngx_event_t *rev, *wev; ngx_int_t rc; u_char *connstring, *last; size_t len; dd("entering"); #if defined(nginx_version) && (nginx_version < 8017) if (data == NULL) { goto failed; } pgctx = ngx_http_get_module_ctx(pgdt->request, ngx_postgres_module); #endif pgscf = pgdt->srv_conf; pgdt->failed = 0; if (pgscf->max_cached && pgscf->single) { rc = ngx_postgres_keepalive_get_peer_single(pc, pgdt, pgscf); if (rc != NGX_DECLINED) { /* re-use keepalive peer */ dd("re-using keepalive peer (single)"); pgdt->state = state_db_send_query; ngx_postgres_process_events(pgdt->request); dd("returning NGX_AGAIN"); return NGX_AGAIN; } } peers = pgscf->peers; if (pgscf->current > peers->number - 1) { pgscf->current = 0; } peer = &peers->peer[pgscf->current++]; pgdt->name.len = peer->name.len; pgdt->name.data = peer->name.data; pgdt->sockaddr = *peer->sockaddr; pc->name = &pgdt->name; pc->sockaddr = &pgdt->sockaddr; pc->socklen = peer->socklen; pc->cached = 0; if ((pgscf->max_cached) && (!pgscf->single)) { rc = ngx_postgres_keepalive_get_peer_multi(pc, pgdt, pgscf); if (rc != NGX_DECLINED) { /* re-use keepalive peer */ dd("re-using keepalive peer (multi)"); pgdt->state = state_db_send_query; ngx_postgres_process_events(pgdt->request); dd("returning NGX_AGAIN"); return NGX_AGAIN; } } if ((pgscf->reject) && (pgscf->active_conns >= pgscf->max_cached)) { ngx_log_error(NGX_LOG_INFO, pc->log, 0, "postgres: keepalive connection pool is full," " rejecting request to upstream \"%V\"", &peer->name); /* a bit hack-ish way to return error response (setup part) */ pc->connection = ngx_get_connection(0, pc->log); #if defined(nginx_version) && (nginx_version < 8017) pgctx->status = NGX_HTTP_SERVICE_UNAVAILABLE; #endif dd("returning NGX_AGAIN (NGX_HTTP_SERVICE_UNAVAILABLE)"); return NGX_AGAIN; } /* sizeof("...") - 1 + 1 (for spaces and '\0' omitted */ len = sizeof("hostaddr=") + peer->host.len + sizeof("port=") + sizeof("65535") - 1 + sizeof("dbname=") + peer->dbname.len + sizeof("user="******"password="******"sslmode=disable"); connstring = ngx_pnalloc(pgdt->request->pool, len); if (connstring == NULL) { #if defined(nginx_version) && (nginx_version >= 8017) dd("returning NGX_ERROR"); return NGX_ERROR; #else goto failed; #endif } /* TODO add unix sockets */ last = ngx_snprintf(connstring, len - 1, "hostaddr=%V port=%d dbname=%V user=%V password=%V" " sslmode=disable", &peer->host, peer->port, &peer->dbname, &peer->user, &peer->password); *last = '\0'; dd("PostgreSQL connection string: %s", connstring); /* * internal checks in PQsetnonblocking are taking care of any * PQconnectStart failures, so we don't need to check them here. */ pgdt->pgconn = PQconnectStart((const char *)connstring); if (PQsetnonblocking(pgdt->pgconn, 1) == -1) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "postgres: connection failed: %s in upstream \"%V\"", PQerrorMessage(pgdt->pgconn), &peer->name); PQfinish(pgdt->pgconn); pgdt->pgconn = NULL; #if defined(nginx_version) && (nginx_version >= 8017) dd("returning NGX_DECLINED"); return NGX_DECLINED; #else pgctx->status = NGX_HTTP_BAD_GATEWAY; goto failed; #endif } #if defined(DDEBUG) && (DDEBUG > 1) PQtrace(pgdt->pgconn, stderr); #endif /* take spot in keepalive connection pool */ pgscf->active_conns++; /* add the file descriptor (fd) into an nginx connection structure */ fd = PQsocket(pgdt->pgconn); if (fd == -1) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "postgres: failed to get connection fd"); goto invalid; } pgxc = pc->connection = ngx_get_connection(fd, pc->log); if (pgxc == NULL) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "postgres: failed to get a free nginx connection"); goto invalid; } pgxc->log = pc->log; pgxc->log_error = pc->log_error; pgxc->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); rev = pgxc->read; wev = pgxc->write; rev->log = pc->log; wev->log = pc->log; /* register the connection with postgres connection fd into the * nginx event model */ if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { dd("NGX_USE_RTSIG_EVENT"); rc = ngx_add_conn(pgxc); } else if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { dd("NGX_USE_CLEAR_EVENT"); rc = ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT); if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "postgres: failed to add nginx connection"); goto invalid; } } else { dd("NGX_LEVEL_EVENT"); rc = ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT); } if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "postgres: failed to add nginx connection"); goto invalid; } pgxc->log->action = "connecting to PostgreSQL database"; pgdt->state = state_db_connect; dd("returning NGX_AGAIN"); return NGX_AGAIN; invalid: ngx_postgres_upstream_free_connection(pc->log, pc->connection, pgdt->pgconn, pgscf); #if defined(nginx_version) && (nginx_version >= 8017) dd("returning NGX_ERROR"); return NGX_ERROR; #else failed: /* a bit hack-ish way to return error response (setup part) */ pc->connection = ngx_get_connection(0, pc->log); dd("returning NGX_AGAIN (NGX_ERROR)"); return NGX_AGAIN; #endif }
void ngx_event_accept(ngx_event_t *ev) { socklen_t socklen; ngx_err_t err; ngx_log_t *log; ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_sockaddr_t sa; ngx_listening_t *ls; ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; #if (NGX_HAVE_ACCEPT4) static ngx_uint_t use_accept4 = 1; #endif if (ev->timedout) { if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { return; } ev->timedout = 0; } ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept; } 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->addr_text, ev->available); do { socklen = sizeof(ngx_sockaddr_t); #if (NGX_HAVE_ACCEPT4) if (use_accept4) { s = accept4(lc->fd, &sa.sockaddr, &socklen, SOCK_NONBLOCK); } else { s = accept(lc->fd, &sa.sockaddr, &socklen); } #else s = accept(lc->fd, &sa.sockaddr, &socklen); #endif if (s == (ngx_socket_t) -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, "accept() not ready"); return; } level = NGX_LOG_ALERT; if (err == NGX_ECONNABORTED) { level = NGX_LOG_ERR; } else if (err == NGX_EMFILE || err == NGX_ENFILE) { level = NGX_LOG_CRIT; } #if (NGX_HAVE_ACCEPT4) ngx_log_error(level, ev->log, err, use_accept4 ? "accept4() failed" : "accept() failed"); if (use_accept4 && err == NGX_ENOSYS) { use_accept4 = 0; ngx_inherited_nonblocking = 0; continue; } #else ngx_log_error(level, ev->log, err, "accept() failed"); #endif if (err == NGX_ECONNABORTED) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } if (ev->available) { continue; } } if (err == NGX_EMFILE || err == NGX_ENFILE) { if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1) != NGX_OK) { return; } if (ngx_use_accept_mutex) { if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); ngx_accept_mutex_held = 0; } ngx_accept_disabled = 1; } else { ngx_add_timer(ev, ecf->accept_mutex_delay); } } return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; c = ngx_get_connection(s, ev->log); 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"); } return; } c->type = SOCK_STREAM; #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); if (c->pool == NULL) { ngx_close_accepted_connection(c); return; } c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(c->sockaddr, &sa, socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { ngx_close_accepted_connection(c); return; } /* set a blocking mode for iocp and non-blocking mode for others */ if (ngx_inherited_nonblocking) { if (ngx_event_flags & NGX_USE_IOCP_EVENT) { if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " failed"); ngx_close_accepted_connection(c); return; } } } else { if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " failed"); ngx_close_accepted_connection(c); return; } } } *log = ls->log; c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->log = log; c->pool->log = log; c->socklen = socklen; c->listening = ls; c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; #if (NGX_HAVE_UNIX_DOMAIN) if (c->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } #endif rev = c->read; wev = c->write; wev->ready = 1; if (ngx_event_flags & NGX_USE_IOCP_EVENT) { rev->ready = 1; } if (ev->deferred_accept) { rev->ready = 1; #if (NGX_HAVE_KQUEUE) rev->available = 1; #endif } rev->log = log; wev->log = log; /* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; } } #if (NGX_DEBUG) { ngx_str_t addr; u_char text[NGX_SOCKADDR_STRLEN]; ngx_debug_accepted_connection(ecf, c); if (log->log_level & NGX_LOG_DEBUG_EVENT) { addr.data = text; addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, "*%uA accept: %V fd:%d", c->number, &addr, s); } } #endif if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { ngx_close_accepted_connection(c); return; } } log->data = NULL; log->handler = NULL; ls->handler(c); if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } } while (ev->available); }
static ngx_int_t ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_int_t rc; ngx_buf_t *b; ngx_str_t *sub; ngx_uint_t flush, last; ngx_chain_t *cl; ngx_http_sub_ctx_t *ctx; ngx_http_sub_match_t *match; ngx_http_sub_loc_conf_t *slcf; ctx = ngx_http_get_module_ctx(r, ngx_http_sub_filter_module); if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } if ((in == NULL && ctx->buf == NULL && ctx->in == NULL && ctx->busy == NULL)) { return ngx_http_next_body_filter(r, in); } if (ctx->once && (ctx->buf == NULL || ctx->in == NULL)) { if (ctx->busy) { if (ngx_http_sub_output(r, ctx) == NGX_ERROR) { return NGX_ERROR; } } return ngx_http_next_body_filter(r, in); } /* add the incoming chain to the chain ctx->in */ if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http sub filter \"%V\"", &r->uri); flush = 0; last = 0; while (ctx->in || ctx->buf) { if (ctx->buf == NULL) { ctx->buf = ctx->in->buf; ctx->in = ctx->in->next; ctx->pos = ctx->buf->pos; } if (ctx->buf->flush || ctx->buf->recycled) { flush = 1; } if (ctx->in == NULL) { last = flush; } b = NULL; while (ctx->pos < ctx->buf->last) { rc = ngx_http_sub_parse(r, ctx, last); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "parse: %i, looked: \"%V\" %p-%p", rc, &ctx->looked, ctx->copy_start, ctx->copy_end); if (rc == NGX_ERROR) { return rc; } if (ctx->saved.len) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "saved: \"%V\"", &ctx->saved); cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = ngx_pnalloc(r->pool, ctx->saved.len); if (b->pos == NULL) { return NGX_ERROR; } ngx_memcpy(b->pos, ctx->saved.data, ctx->saved.len); b->last = b->pos + ctx->saved.len; b->memory = 1; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->saved.len = 0; } if (ctx->copy_start != ctx->copy_end) { cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } b = cl->buf; ngx_memcpy(b, ctx->buf, sizeof(ngx_buf_t)); b->pos = ctx->copy_start; b->last = ctx->copy_end; b->shadow = NULL; b->last_buf = 0; b->last_in_chain = 0; b->recycled = 0; if (b->in_file) { b->file_last = b->file_pos + (b->last - ctx->buf->pos); b->file_pos += b->pos - ctx->buf->pos; } *ctx->last_out = cl; ctx->last_out = &cl->next; } if (rc == NGX_AGAIN) { continue; } /* rc == NGX_OK */ cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); if (ctx->sub == NULL) { ctx->sub = ngx_pcalloc(r->pool, sizeof(ngx_str_t) * ctx->matches->nelts); if (ctx->sub == NULL) { return NGX_ERROR; } } sub = &ctx->sub[ctx->index]; if (sub->data == NULL) { match = ctx->matches->elts; if (ngx_http_complex_value(r, match[ctx->index].value, sub) != NGX_OK) { return NGX_ERROR; } } if (sub->len) { b->memory = 1; b->pos = sub->data; b->last = sub->data + sub->len; } else { b->sync = 1; } *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->index = 0; ctx->once = slcf->once && (++ctx->applied == ctx->matches->nelts); continue; } if (ctx->looked.len && (ctx->buf->last_buf || ctx->buf->last_in_chain)) { cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->pos = ctx->looked.data; b->last = b->pos + ctx->looked.len; b->memory = 1; *ctx->last_out = cl; ctx->last_out = &cl->next; ctx->looked.len = 0; } if (ctx->buf->last_buf || ctx->buf->flush || ctx->buf->sync || ngx_buf_in_memory(ctx->buf)) { if (b == NULL) { cl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (cl == NULL) { return NGX_ERROR; } b = cl->buf; ngx_memzero(b, sizeof(ngx_buf_t)); b->sync = 1; *ctx->last_out = cl; ctx->last_out = &cl->next; } b->last_buf = ctx->buf->last_buf; b->last_in_chain = ctx->buf->last_in_chain; b->flush = ctx->buf->flush; b->shadow = ctx->buf; b->recycled = ctx->buf->recycled; } ctx->buf = NULL; } if (ctx->out == NULL && ctx->busy == NULL) { return NGX_OK; } return ngx_http_sub_output(r, ctx); }
static ngx_buf_t * ngx_http_pngquant_quantize(ngx_http_request_t *r, ngx_http_pngquant_ctx_t *ctx) { u_char *out; ngx_buf_t *b; ngx_pool_cleanup_t *cln; ngx_http_pngquant_conf_t *conf; gdImagePtr img; int size; ngx_int_t rc; ngx_temp_file_t *tf; ssize_t n; ngx_ext_rename_file_t ext; ngx_str_t dest; ngx_str_t value; img = gdImageCreateFromPngPtr(ctx->length, ctx->image); if (img == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gdImageCreateFromPngPtr() failed"); return NULL; } conf = ngx_http_get_module_loc_conf(r, ngx_http_pngquant_module); /* * gdImageTrueColorToPaletteSetMethod(img, GD_QUANT_LIQ, conf->speed); * gdImageTrueColorToPalette(img, conf->dither, conf->colors); */ ngx_pngquant_gd_image(img, conf->dither, conf->colors, conf->speed); out = gdImagePngPtr(img, &size); gdImageDestroy(img); ngx_pfree(r->pool, ctx->image); if (out == NULL) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "gdImagePngPtr() failed"); return NULL; } if (conf->store) { if(ngx_http_complex_value(r, conf->store, &value) != NGX_OK) { goto failed; } dest.len = value.len + 1; dest.data = ngx_pnalloc(r->pool, dest.len); if (dest.data == NULL) { goto failed; } ngx_memzero(dest.data, dest.len); ngx_memcpy(dest.data, value.data, value.len); ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "pngquant_store (%s)", dest.data); tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); if (tf == NULL) { goto failed; } tf->file.fd = NGX_INVALID_FILE; tf->file.log = r->connection->log; tf->path = conf->temp_path; tf->pool = r->pool; tf->persistent = 1; rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool, tf->persistent, tf->clean, tf->access); if (rc != NGX_OK) { goto failed; } n = ngx_write_fd(tf->file.fd, out, size); if (n == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_write_fd_n " \"%s\" failed", tf->file.name.data); goto failed; } if ((int) n != size) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_write_fd_n " has written only %z of %uz bytes", n, size); goto failed; } ext.access = conf->store_access; ext.path_access = conf->store_access; ext.time = -1; ext.create_path = 1; ext.delete_file = 1; ext.log = r->connection->log; rc = ngx_ext_rename_file(&tf->file.name, &dest, &ext); if (rc != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_ext_rename_file() failed"); goto failed; } } cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { goto failed; } b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { goto failed; } cln->handler = ngx_http_pngquant_cleanup; cln->data = out; b->pos = out; b->last = out + size; b->memory = 1; b->last_buf = 1; ngx_http_pngquant_length(r, b); #if defined(nginx_version) && (nginx_version >= 1007003) ngx_http_weak_etag(r); #endif return b; failed: gdFree(out); return NULL; }
static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn) { u_char *file; ngx_slab_pool_t *sp; sp = (ngx_slab_pool_t *) zn->shm.addr; if (zn->shm.exists) { if (sp == sp->addr) { return NGX_OK; } #if (NGX_WIN32) /* remap at the required address */ if (ngx_shm_remap(&zn->shm, sp->addr) != NGX_OK) { return NGX_ERROR; } sp = (ngx_slab_pool_t *) zn->shm.addr; if (sp == sp->addr) { return NGX_OK; } #endif ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "shared zone \"%V\" has no equal addresses: %p vs %p", &zn->shm.name, sp->addr, sp); return NGX_ERROR; } sp->end = zn->shm.addr + zn->shm.size; sp->min_shift = 3; sp->addr = zn->shm.addr; #if (NGX_HAVE_ATOMIC_OPS) file = NULL; #else file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len); if (file == NULL) { return NGX_ERROR; } (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name); #endif if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) { return NGX_ERROR; } ngx_slab_init(sp); return NGX_OK; }
static ngx_int_t ngx_http_sub_header_filter(ngx_http_request_t *r) { ngx_str_t *m; ngx_uint_t i, j, n; ngx_http_sub_ctx_t *ctx; ngx_http_sub_pair_t *pairs; ngx_http_sub_match_t *matches; ngx_http_sub_loc_conf_t *slcf; slcf = ngx_http_get_module_loc_conf(r, ngx_http_sub_filter_module); if (slcf->pairs == NULL || r->headers_out.content_length_n == 0 || ngx_http_test_content_type(r, &slcf->types) == NULL) { return ngx_http_next_header_filter(r); } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } if (slcf->dynamic == 0) { ctx->tables = slcf->tables; ctx->matches = slcf->matches; } else { pairs = slcf->pairs->elts; n = slcf->pairs->nelts; matches = ngx_pcalloc(r->pool, sizeof(ngx_http_sub_match_t) * n); if (matches == NULL) { return NGX_ERROR; } j = 0; for (i = 0; i < n; i++) { matches[j].value = &pairs[i].value; if (pairs[i].match.lengths == NULL) { matches[j].match = pairs[i].match.value; j++; continue; } m = &matches[j].match; if (ngx_http_complex_value(r, &pairs[i].match, m) != NGX_OK) { return NGX_ERROR; } if (m->len == 0) { continue; } ngx_strlow(m->data, m->data, m->len); j++; } if (j == 0) { return ngx_http_next_header_filter(r); } ctx->matches = ngx_palloc(r->pool, sizeof(ngx_array_t)); if (ctx->matches == NULL) { return NGX_ERROR; } ctx->matches->elts = matches; ctx->matches->nelts = j; ctx->tables = ngx_palloc(r->pool, sizeof(ngx_http_sub_tables_t)); if (ctx->tables == NULL) { return NGX_ERROR; } ngx_http_sub_init_tables(ctx->tables, ctx->matches->elts, ctx->matches->nelts); } ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module); ctx->saved.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1); if (ctx->saved.data == NULL) { return NGX_ERROR; } ctx->looked.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1); if (ctx->looked.data == NULL) { return NGX_ERROR; } ctx->offset = ctx->tables->min_match_len - 1; ctx->last_out = &ctx->out; r->filter_need_in_memory = 1; if (r == r->main) { ngx_http_clear_content_length(r); if (!slcf->last_modified) { ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); } else { ngx_http_weak_etag(r); } } return ngx_http_next_header_filter(r); }
static int ngx_http_multiple_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { ngx_connection_t *c; ngx_http_connection_t *hc; const char *servername; ngx_str_t cert; ngx_str_t key; ngx_str_t host; ngx_http_multiple_ssl_srv_conf_t *mscf; c = ngx_ssl_get_connection(ssl_conn); if (c == NULL) { return 0; } hc = c->data; if (NULL == hc) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "multiple ssl connection data hc NULL"); return 0; } servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); if (servername == NULL) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl SSL_get_servername NULL"); return SSL_TLSEXT_ERR_NOACK; } host.len = ngx_strlen(servername); if (host.len == 0) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl servername len == 0"); return SSL_TLSEXT_ERR_NOACK; } host.data = (u_char *) servername; ngx_log_error(NGX_LOG_INFO, c->log, 0, "multiple ssl servername \"%V\"", &host); mscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_multiple_ssl_module); if (NULL == mscf) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl mscf NULL"); return SSL_TLSEXT_ERR_NOACK; } if (!mscf->multiple_ssl_enable) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl multiple_ssl_enable OFF"); return SSL_TLSEXT_ERR_NOACK; } cert.len = mscf->multiple_ssl_cert_path.len + 2 + host.len + ngx_strlen(".cert.der"); key.len = mscf->multiple_ssl_cert_path.len + 2 + host.len + ngx_strlen(".key.der"); cert.data = ngx_pnalloc(c->pool, cert.len); if (NULL == cert.data) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl cert.data NULL"); return SSL_TLSEXT_ERR_NOACK; } ngx_memzero(cert.data, cert.len); ngx_sprintf(cert.data, "%V/%V.cert.der", &mscf->multiple_ssl_cert_path, &host); *(cert.data+cert.len) = 0; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl cert %V", &cert); key.data = ngx_pnalloc(c->pool, key.len+1); if (NULL == key.data) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "multiple ssl key.data NULL"); return SSL_TLSEXT_ERR_NOACK; } ngx_memzero(key.data, key.len); ngx_sprintf(key.data, "%V/%V.key.der", &mscf->multiple_ssl_cert_path, &host); *(key.data+key.len) = 0; if (0 != access((const char *)cert.data, F_OK|R_OK)) { ngx_log_debug1(NGX_LOG_WARN, c->log, 0, "multiple ssl cert [%V] not exists or not read", &cert); return SSL_TLSEXT_ERR_NOACK; } ngx_http_multiple_ssl_set_der_certificate(ssl_conn, &cert, &key); return SSL_TLSEXT_ERR_OK; }
ngx_int_t ngx_http_sticky_misc_set_cookie(ngx_http_request_t *r, ngx_str_t *name, ngx_str_t *value, ngx_str_t *domain, ngx_str_t *path, time_t expires) { u_char *cookie, *p; size_t len; ngx_table_elt_t *set_cookie, *elt; ngx_str_t remove; ngx_list_part_t *part; ngx_uint_t i; if (value == NULL) { ngx_str_set(&remove, "_remove_"); value = &remove; } /* name = value */ len = name->len + 1 + value->len; /*; Domain= */ if (domain->len > 0) { len += sizeof("; Domain=") - 1 + domain->len; } /*; Max-Age= */ if (expires != NGX_CONF_UNSET) { len += sizeof("; Max-Age=") - 1 + NGX_TIME_T_LEN; } /* ; Path= */ if (path->len > 0) { len += sizeof("; Path=") - 1 + path->len; } cookie = ngx_pnalloc(r->pool, len); if (cookie == NULL) { return NGX_ERROR; } p = ngx_copy(cookie, name->data, name->len); *p++ = '='; p = ngx_copy(p, value->data, value->len); if (domain->len > 0) { p = ngx_copy(p, "; Domain=", sizeof("; Domain=") - 1); p = ngx_copy(p, domain->data, domain->len); } if (expires != NGX_CONF_UNSET) { p = ngx_copy(p, "; Max-Age=", sizeof("; Max-Age=") - 1); p = ngx_snprintf(p, NGX_TIME_T_LEN, "%T", expires); } if (path->len > 0) { p = ngx_copy(p, "; Path=", sizeof("; Path=") - 1); p = ngx_copy(p, path->data, path->len); } part = &r->headers_out.headers.part; elt = part->elts; set_cookie = NULL; for (i=0 ;; i++) { if (part->nelts > 1 || i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; elt = part->elts; i = 0; } /* ... */ if (ngx_strncmp(elt->value.data, name->data, name->len) == 0) { set_cookie = elt; break; } } /* found a Set-Cookie header with the same name: replace it */ if (set_cookie != NULL) { set_cookie->value.len = p - cookie; set_cookie->value.data = cookie; return NGX_OK; } set_cookie = ngx_list_push(&r->headers_out.headers); if (set_cookie == NULL) { return NGX_ERROR; } set_cookie->hash = 1; ngx_str_set(&set_cookie->key, "Set-Cookie"); set_cookie->value.len = p - cookie; set_cookie->value.data = cookie; return NGX_OK; }
ngx_http_variable_t * ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags) { ngx_int_t rc; ngx_uint_t i; ngx_hash_key_t *key; ngx_http_variable_t *v; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); key = cmcf->variables_keys->keys.elts; for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) { if (name->len != key[i].key.len || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0) { continue; } v = key[i].value; if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the duplicate \"%V\" variable", name); return NULL; } return v; } v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t)); if (v == NULL) { return NULL; } v->name.len = name->len; v->name.data = ngx_pnalloc(cf->pool, name->len); if (v->name.data == NULL) { return NULL; } ngx_strlow(v->name.data, name->data, name->len); v->set_handler = NULL; v->get_handler = NULL; v->data = 0; v->flags = flags; v->index = 0; rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0); if (rc == NGX_ERROR) { return NULL; } if (rc == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting variable name \"%V\"", name); return NULL; } return v; }
static ngx_int_t ngx_http_random_index_handler(ngx_http_request_t *r) { u_char *last, *filename; size_t len, allocated, root; ngx_err_t err; ngx_int_t rc; ngx_str_t path, uri, *name; ngx_dir_t dir; ngx_uint_t n, level; ngx_array_t names; ngx_http_random_index_loc_conf_t *rlcf; if (r->uri.data[r->uri.len - 1] != '/') { return NGX_DECLINED; } if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { return NGX_DECLINED; } rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); if (!rlcf->enable) { return NGX_DECLINED; } #if (NGX_HAVE_D_TYPE) len = NGX_DIR_MASK_LEN; #else len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; #endif last = ngx_http_map_uri_to_path(r, &path, &root, len); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } allocated = path.len; path.len = last - path.data - 1; path.data[path.len] = '\0'; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index: \"%s\"", path.data); if (ngx_open_dir(&path, &dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) { level = NGX_LOG_ERR; rc = NGX_HTTP_NOT_FOUND; } else if (err == NGX_EACCES) { level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; } else { level = NGX_LOG_CRIT; rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_log_error(level, r->connection->log, err, ngx_open_dir_n " \"%s\" failed", path.data); return rc; } if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { return ngx_http_random_index_error(r, &dir, &path); } filename = path.data; filename[path.len] = '/'; for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err != NGX_ENOMOREFILES) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_read_dir_n " \"%V\" failed", &path); return ngx_http_random_index_error(r, &dir, &path); } break; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http random index file: \"%s\"", ngx_de_name(&dir)); if (ngx_de_name(&dir)[0] == '.') { continue; } len = ngx_de_namelen(&dir); if (dir.type == 0 || ngx_de_is_link(&dir)) { /* 1 byte for '/' and 1 byte for terminating '\0' */ if (path.len + 1 + len + 1 > allocated) { allocated = path.len + 1 + len + 1 + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; filename = ngx_pnalloc(r->pool, allocated); if (filename == NULL) { return ngx_http_random_index_error(r, &dir, &path); } last = ngx_cpystrn(filename, path.data, path.len + 1); *last++ = '/'; } ngx_cpystrn(last, ngx_de_name(&dir), len + 1); if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, ngx_de_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_de_link_info_n " \"%s\" failed", filename); return ngx_http_random_index_error(r, &dir, &path); } } } if (!ngx_de_is_file(&dir)) { continue; } name = ngx_array_push(&names); if (name == NULL) { return ngx_http_random_index_error(r, &dir, &path); } name->len = len; name->data = ngx_pnalloc(r->pool, len); if (name->data == NULL) { return ngx_http_random_index_error(r, &dir, &path); } ngx_memcpy(name->data, ngx_de_name(&dir), len); } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", &path); } n = names.nelts; if (n == 0) { return NGX_DECLINED; } name = names.elts; n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); uri.len = r->uri.len + name[n].len; uri.data = ngx_pnalloc(r->pool, uri.len); if (uri.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } last = ngx_copy(uri.data, r->uri.data, r->uri.len); ngx_memcpy(last, name[n].data, name[n].len); return ngx_http_internal_redirect(r, &uri, &r->args); }
// make our proposed ZIP-file chunk map ngx_int_t ngx_http_zip_generate_pieces(ngx_http_request_t *r, ngx_http_zip_ctx_t *ctx) { ngx_uint_t i, piece_i; off_t offset = 0; ngx_http_zip_file_t *file; ngx_http_zip_piece_t *header_piece, *file_piece, *trailer_piece, *cd_piece; ngx_http_variable_value_t *vv; if ((vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t))) == NULL) return NGX_ERROR; ctx->unicode_path = 0; #ifdef NGX_ZIP_HAVE_ICONV iconv_t *iconv_cd = NULL; if (ngx_http_upstream_header_variable(r, vv, (uintptr_t)(&ngx_http_zip_header_charset_name)) == NGX_OK && !vv->not_found && ngx_strncmp(vv->data, "utf8", sizeof("utf8") - 1) != 0) { char encoding[ICONV_CSNMAXLEN]; snprintf(encoding, sizeof(encoding), "%s//TRANSLIT//IGNORE", vv->data); iconv_cd = iconv_open((const char *)encoding, "utf-8"); if (iconv_cd == (iconv_t)(-1)) { ngx_log_error(NGX_LOG_WARN, r->connection->log, errno, "mod_zip: iconv_open('%s', 'utf-8') failed", vv->data); iconv_cd = NULL; } } if (iconv_cd) { ctx->unicode_path = 1; } #endif // pieces: for each file: header, data, footer (if needed) -> 2 or 3 per file // plus file footer (CD + [zip64 end + zip64 locator +] end of cd) in one chunk ctx->pieces_n = ctx->files.nelts * (2 + (!!ctx->missing_crc32)) + 1; if ((ctx->pieces = ngx_palloc(r->pool, sizeof(ngx_http_zip_piece_t) * ctx->pieces_n)) == NULL) return NGX_ERROR; ctx->cd_size = 0; for (piece_i = i = 0; i < ctx->files.nelts; i++) { file = &((ngx_http_zip_file_t *)ctx->files.elts)[i]; file->offset = offset; #ifdef NGX_ZIP_HAVE_ICONV if (ctx->unicode_path) { size_t inlen = file->filename.len, outlen, outleft; u_char *p, *in; //inbuf file->filename_utf8.data = ngx_pnalloc(r->pool, file->filename.len + 1); ngx_memcpy(file->filename_utf8.data, file->filename.data, file->filename.len); file->filename_utf8.len = file->filename.len; file->filename_utf8.data[file->filename.len] = '\0'; //outbuf outlen = outleft = inlen * sizeof(int) + 15; file->filename.data = ngx_pnalloc(r->pool, outlen + 1); in = file->filename_utf8.data; p = file->filename.data; //reset state iconv(iconv_cd, NULL, NULL, NULL, NULL); //convert the string iconv(iconv_cd, (char **)&in, &inlen, (char **)&p, &outleft); //XXX if (res == (size_t)-1) { ? } file->filename.len = outlen - outleft; file->filename_utf8_crc32 = ngx_crc32_long(file->filename_utf8.data, file->filename_utf8.len); } #endif if(offset >= (off_t) NGX_MAX_UINT32_VALUE) ctx->zip64_used = file->need_zip64_offset = 1; if(file->size >= (off_t) NGX_MAX_UINT32_VALUE) ctx->zip64_used = file->need_zip64 = 1; ctx->cd_size += sizeof(ngx_zip_central_directory_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_central_t) + (file->need_zip64_offset ? (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_offset_t) : sizeof(ngx_zip_extra_field_zip64_offset_only_t)) : (file->need_zip64 ? sizeof(ngx_zip_extra_field_zip64_sizes_only_t) : 0) + (ctx->unicode_path ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0) ); header_piece = &ctx->pieces[piece_i++]; header_piece->type = zip_header_piece; header_piece->file = file; header_piece->range.start = offset; header_piece->range.end = offset += sizeof(ngx_zip_local_file_header_t) + file->filename.len + sizeof(ngx_zip_extra_field_local_t) + (file->need_zip64? sizeof(ngx_zip_extra_field_zip64_sizes_only_t):0) + (ctx->unicode_path ? (sizeof(ngx_zip_extra_field_unicode_path_t) + file->filename_utf8.len): 0); file_piece = &ctx->pieces[piece_i++]; file_piece->type = zip_file_piece; file_piece->file = file; file_piece->range.start = offset; file_piece->range.end = offset += file->size; //!note: (sizeless chunks): we need file size here / or mark it and modify ranges after if (file->missing_crc32) { // if incomplete header -> add footer with that info to file trailer_piece = &ctx->pieces[piece_i++]; trailer_piece->type = zip_trailer_piece; trailer_piece->file = file; trailer_piece->range.start = offset; trailer_piece->range.end = offset += file->need_zip64? sizeof(ngx_zip_data_descriptor_zip64_t) : sizeof(ngx_zip_data_descriptor_t); //!!TODO: if we want Ranges support - here we know it is impossible for this set //? check conf/some state and abort? } } #ifdef NGX_ZIP_HAVE_ICONV if (ctx->unicode_path) { iconv_close(iconv_cd); } #endif ctx->zip64_used |= offset >= (off_t) NGX_MAX_UINT32_VALUE || ctx->files.nelts >= NGX_MAX_UINT16_VALUE; ctx->cd_size += sizeof(ngx_zip_end_of_central_directory_record_t); if (ctx->zip64_used) ctx->cd_size += sizeof(ngx_zip_zip64_end_of_central_directory_record_t) + sizeof(ngx_zip_zip64_end_of_central_directory_locator_t); cd_piece = &ctx->pieces[piece_i++]; cd_piece->type = zip_central_directory_piece; cd_piece->range.start = offset; cd_piece->range.end = offset += ctx->cd_size; ctx->pieces_n = piece_i; //!! nasty hack (truncating allocated array without reallocation) ctx->archive_size = offset; return NGX_OK; }
static ngx_int_t ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last) { size_t left, n, size; u_char *dst, *p; enum { sw_start = 0, sw_header, /* handshake msg_type, length */ sw_head_tail, /* version, random */ sw_sid_len, /* session_id length */ sw_sid, /* session_id */ sw_cs_len, /* cipher_suites length */ sw_cs, /* cipher_suites */ sw_cm_len, /* compression_methods length */ sw_cm, /* compression_methods */ sw_ext, /* extension */ sw_ext_header, /* extension_type, extension_data length */ sw_sni_len, /* SNI length */ sw_sni_host_head, /* SNI name_type, host_name length */ sw_sni_host /* SNI host_name */ } state; ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: state %ui left %z", ctx->state, ctx->left); state = ctx->state; size = ctx->size; left = ctx->left; dst = ctx->dst; p = ctx->buf; for ( ;; ) { n = ngx_min((size_t) (last - pos), size); if (dst) { dst = ngx_cpymem(dst, pos, n); } pos += n; size -= n; left -= n; if (size != 0) { break; } switch (state) { case sw_start: state = sw_header; dst = p; size = 4; left = size; break; case sw_header: if (p[0] != 1) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: not a client hello"); return NGX_DECLINED; } state = sw_head_tail; dst = NULL; size = 34; left = (p[1] << 16) + (p[2] << 8) + p[3]; break; case sw_head_tail: state = sw_sid_len; dst = p; size = 1; break; case sw_sid_len: state = sw_sid; dst = NULL; size = p[0]; break; case sw_sid: state = sw_cs_len; dst = p; size = 2; break; case sw_cs_len: state = sw_cs; dst = NULL; size = (p[0] << 8) + p[1]; break; case sw_cs: state = sw_cm_len; dst = p; size = 1; break; case sw_cm_len: state = sw_cm; dst = NULL; size = p[0]; break; case sw_cm: if (left == 0) { /* no extensions */ return NGX_OK; } state = sw_ext; dst = p; size = 2; break; case sw_ext: if (left == 0) { return NGX_OK; } state = sw_ext_header; dst = p; size = 4; break; case sw_ext_header: if (p[0] == 0 && p[1] == 0) { /* SNI extension */ state = sw_sni_len; dst = NULL; size = 2; break; } state = sw_ext; dst = NULL; size = (p[2] << 8) + p[3]; break; case sw_sni_len: state = sw_sni_host_head; dst = p; size = 3; break; case sw_sni_host_head: if (p[0] != 0) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: SNI hostname type is not DNS"); return NGX_DECLINED; } state = sw_sni_host; size = (p[1] << 8) + p[2]; ctx->host.data = ngx_pnalloc(ctx->pool, size); if (ctx->host.data == NULL) { return NGX_ERROR; } dst = ctx->host.data; break; case sw_sni_host: ctx->host.len = (p[1] << 8) + p[2]; ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: SNI hostname \"%V\"", &ctx->host); return NGX_OK; } if (left < size) { ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0, "ssl preread: failed to parse handshake"); return NGX_DECLINED; } } ctx->state = state; ctx->size = size; ctx->left = left; ctx->dst = dst; return NGX_AGAIN; }
ngx_int_t ngx_tcp_log_handler(ngx_tcp_session_t *s) { u_char *line, *p; size_t len; ngx_uint_t l; ngx_connection_t *c; ngx_tcp_log_t *log; ngx_open_file_t *file; #if (nginx_version) >= 1003010 ngx_tcp_log_buf_t *buffer; #endif ngx_tcp_log_srv_conf_t *lscf; ngx_tcp_core_srv_conf_t *cscf; ngx_log_debug0(NGX_LOG_DEBUG_TCP, s->connection->log, 0, "tcp access log handler"); cscf = ngx_tcp_get_module_srv_conf(s, ngx_tcp_core_module); lscf = cscf->access_log; if (lscf->off) { return NGX_OK; } c = s->connection; log = lscf->logs->elts; for (l = 0; l < lscf->logs->nelts; l++) { if (ngx_time() == log[l].disk_full_time) { /* * on FreeBSD writing to a full filesystem with enabled softupdates * may block process for much longer time than writing to non-full * filesystem, so we skip writing to a log for one second */ continue; } len = 0; /* Calculate the length */ len += sizeof("1970/09/28 12:00:00"); /* log time */ len += NGX_INT64_LEN + 2; /* [ngx_pid] */ len += c->addr_text.len + 1; /* client address */ len += s->addr_text->len + 1; /* this session address */ len += sizeof("1970/09/28 12:00:00"); /* accept time */ len += sizeof("255.255.255.255:65536"); /* upstream address */ len += NGX_OFF_T_LEN + 1; /* read bytes from client */ len += NGX_OFF_T_LEN + 1; /* write bytes to client */ len += NGX_LINEFEED_SIZE; file = log[l].file; #if (nginx_version) >= 1003010 if (file && file->data) { buffer = file->data; if (len > (size_t) (buffer->last - buffer->pos)) { ngx_tcp_log_write(s, &log[l], buffer->start, buffer->pos - buffer->start); buffer->pos = buffer->start; } if (len <= (size_t) (buffer->last - buffer->pos)) { p = buffer->pos; p = ngx_tcp_log_fill(s, p); buffer->pos = p; continue; } } #else if (file && file->buffer) { if (len > (size_t) (file->last - file->pos)) { ngx_tcp_log_write(s, &log[l], file->buffer, file->pos - file->buffer); file->pos = file->buffer; } if (len <= (size_t) (file->last - file->pos)) { p = file->pos; p = ngx_tcp_log_fill(s, p); file->pos = p; continue; } } #endif line = ngx_pnalloc(s->pool, len); if (line == NULL) { return NGX_ERROR; } p = line; p = ngx_tcp_log_fill(s, p); ngx_tcp_log_write(s, &log[l], line, p - line); } return NGX_OK; }
ngx_int_t ngx_postgres_upstream_init(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *uscf) { ngx_postgres_upstream_srv_conf_t *pgscf; ngx_postgres_upstream_server_t *server; ngx_postgres_upstream_peers_t *peers; ngx_uint_t i, j, n; dd("entering"); uscf->peer.init = ngx_postgres_upstream_init_peer; pgscf = ngx_http_conf_upstream_srv_conf(uscf, ngx_postgres_module); if (pgscf->servers == NULL || pgscf->servers->nelts == 0) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "postgres: no \"postgres_server\" defined" " in upstream \"%V\" in %s:%ui", &uscf->host, uscf->file_name, uscf->line); dd("returning NGX_ERROR"); return NGX_ERROR; } /* pgscf->servers != NULL */ server = uscf->servers->elts; n = 0; for (i = 0; i < uscf->servers->nelts; i++) { n += server[i].naddrs; } peers = ngx_pcalloc(cf->pool, sizeof(ngx_postgres_upstream_peers_t) + sizeof(ngx_postgres_upstream_peer_t) * (n - 1)); if (peers == NULL) { dd("returning NGX_ERROR"); return NGX_ERROR; } peers->single = (n == 1); peers->number = n; peers->name = &uscf->host; n = 0; for (i = 0; i < uscf->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; peers->peer[n].socklen = server[i].addrs[j].socklen; peers->peer[n].name = server[i].addrs[j].name; peers->peer[n].port = server[i].port; peers->peer[n].dbname = server[i].dbname; peers->peer[n].user = server[i].user; peers->peer[n].password = server[i].password; peers->peer[n].host.data = ngx_pnalloc(cf->pool, NGX_SOCKADDR_STRLEN); if (peers->peer[n].host.data == NULL) { dd("returning NGX_ERROR"); return NGX_ERROR; } peers->peer[n].host.len = ngx_sock_ntop(peers->peer[n].sockaddr, peers->peer[n].host.data, NGX_SOCKADDR_STRLEN, 0); if (peers->peer[n].host.len == 0) { dd("returning NGX_ERROR"); return NGX_ERROR; } n++; } } pgscf->peers = peers; pgscf->active_conns = 0; if (pgscf->max_cached) { dd("returning"); return ngx_postgres_keepalive_init(cf->pool, pgscf); } dd("returning NGX_OK"); return NGX_OK; }
static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) { size_t len; time_t now, expires_time, max_age; ngx_uint_t i; ngx_table_elt_t *expires, *cc, **ccp; expires = r->headers_out.expires; if (expires == NULL) { expires = ngx_list_push(&r->headers_out.headers); if (expires == NULL) { return NGX_ERROR; } r->headers_out.expires = expires; expires->hash = 1; ngx_str_set(&expires->key, "Expires"); } len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); expires->value.len = len - 1; ccp = r->headers_out.cache_control.elts; if (ccp == NULL) { if (ngx_array_init(&r->headers_out.cache_control, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK) { return NGX_ERROR; } ccp = ngx_array_push(&r->headers_out.cache_control); if (ccp == NULL) { return NGX_ERROR; } cc = ngx_list_push(&r->headers_out.headers); if (cc == NULL) { return NGX_ERROR; } cc->hash = 1; ngx_str_set(&cc->key, "Cache-Control"); *ccp = cc; } else { for (i = 1; i < r->headers_out.cache_control.nelts; i++) { ccp[i]->hash = 0; } cc = ccp[0]; } if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; ngx_str_set(&cc->value, "no-cache"); return NGX_OK; } if (conf->expires == NGX_HTTP_EXPIRES_MAX) { expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT"; /* 10 years */ ngx_str_set(&cc->value, "max-age=315360000"); return NGX_OK; } expires->value.data = ngx_pnalloc(r->pool, len); if (expires->value.data == NULL) { return NGX_ERROR; } if (conf->expires_time == 0 && conf->expires != NGX_HTTP_EXPIRES_DAILY) { ngx_memcpy(expires->value.data, ngx_cached_http_time.data, ngx_cached_http_time.len + 1); ngx_str_set(&cc->value, "max-age=0"); return NGX_OK; } now = ngx_time(); if (conf->expires == NGX_HTTP_EXPIRES_DAILY) { expires_time = ngx_next_time(conf->expires_time); max_age = expires_time - now; } else if (conf->expires == NGX_HTTP_EXPIRES_ACCESS || r->headers_out.last_modified_time == -1) { expires_time = now + conf->expires_time; max_age = conf->expires_time; } else { expires_time = r->headers_out.last_modified_time + conf->expires_time; max_age = expires_time - now; } ngx_http_time(expires->value.data, expires_time); if (conf->expires_time < 0 || max_age < 0) { ngx_str_set(&cc->value, "no-cache"); return NGX_OK; } cc->value.data = ngx_pnalloc(r->pool, sizeof("max-age=") + NGX_TIME_T_LEN + 1); if (cc->value.data == NULL) { return NGX_ERROR; } cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", max_age) - cc->value.data; return NGX_OK; }
void ngx_event_recvmsg(ngx_event_t *ev) { ssize_t n; ngx_log_t *log; ngx_err_t err; ngx_event_t *rev, *wev; struct iovec iov[1]; struct msghdr msg; ngx_sockaddr_t sa; ngx_listening_t *ls; ngx_event_conf_t *ecf; ngx_connection_t *c, *lc; static u_char buffer[65535]; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) #if (NGX_HAVE_IP_RECVDSTADDR) u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; #elif (NGX_HAVE_IP_PKTINFO) u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; #endif #endif if (ev->timedout) { if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { return; } ev->timedout = 0; } ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept; } lc = ev->data; ls = lc->listening; ev->ready = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "recvmsg on %V, ready: %d", &ls->addr_text, ev->available); do { ngx_memzero(&msg, sizeof(struct msghdr)); iov[0].iov_base = (void *) buffer; iov[0].iov_len = sizeof(buffer); msg.msg_name = &sa; msg.msg_namelen = sizeof(ngx_sockaddr_t); msg.msg_iov = iov; msg.msg_iovlen = 1; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (ls->wildcard) { #if (NGX_HAVE_IP_RECVDSTADDR || NGX_HAVE_IP_PKTINFO) if (ls->sockaddr->sa_family == AF_INET) { msg.msg_control = &msg_control; msg.msg_controllen = sizeof(msg_control); } #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) if (ls->sockaddr->sa_family == AF_INET6) { msg.msg_control = &msg_control6; msg.msg_controllen = sizeof(msg_control6); } #endif } #endif n = recvmsg(lc->fd, &msg, 0); if (n == -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, "recvmsg() not ready"); return; } ngx_log_error(NGX_LOG_ALERT, ev->log, err, "recvmsg() failed"); return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (msg.msg_flags & (MSG_TRUNC|MSG_CTRUNC)) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "recvmsg() truncated data"); continue; } #endif ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; c = ngx_get_connection(lc->fd, ev->log); if (c == NULL) { return; } c->shared = 1; c->type = SOCK_DGRAM; c->socklen = msg.msg_namelen; #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); if (c->pool == NULL) { ngx_close_accepted_connection(c); return; } c->sockaddr = ngx_palloc(c->pool, c->socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(c->sockaddr, msg.msg_name, c->socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { ngx_close_accepted_connection(c); return; } *log = ls->log; c->send = ngx_udp_send; c->log = log; c->pool->log = log; c->listening = ls; c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; #if (NGX_HAVE_MSGHDR_MSG_CONTROL) if (ls->wildcard) { struct cmsghdr *cmsg; struct sockaddr *sockaddr; sockaddr = ngx_palloc(c->pool, c->local_socklen); if (sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(sockaddr, c->local_sockaddr, c->local_socklen); c->local_sockaddr = sockaddr; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { #if (NGX_HAVE_IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR && sockaddr->sa_family == AF_INET) { struct in_addr *addr; struct sockaddr_in *sin; addr = (struct in_addr *) CMSG_DATA(cmsg); sin = (struct sockaddr_in *) sockaddr; sin->sin_addr = *addr; break; } #elif (NGX_HAVE_IP_PKTINFO) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO && sockaddr->sa_family == AF_INET) { struct in_pktinfo *pkt; struct sockaddr_in *sin; pkt = (struct in_pktinfo *) CMSG_DATA(cmsg); sin = (struct sockaddr_in *) sockaddr; sin->sin_addr = pkt->ipi_addr; break; } #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO && sockaddr->sa_family == AF_INET6) { struct in6_pktinfo *pkt6; struct sockaddr_in6 *sin6; pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg); sin6 = (struct sockaddr_in6 *) sockaddr; sin6->sin6_addr = pkt6->ipi6_addr; break; } #endif } } #endif c->buffer = ngx_create_temp_buf(c->pool, n); if (c->buffer == NULL) { ngx_close_accepted_connection(c); return; } c->buffer->last = ngx_cpymem(c->buffer->last, buffer, n); rev = c->read; wev = c->write; wev->ready = 1; rev->log = log; wev->log = log; /* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; } } #if (NGX_DEBUG) { ngx_str_t addr; u_char text[NGX_SOCKADDR_STRLEN]; ngx_debug_accepted_connection(ecf, c); if (log->log_level & NGX_LOG_DEBUG_EVENT) { addr.data = text; addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_debug4(NGX_LOG_DEBUG_EVENT, log, 0, "*%uA recvmsg: %V fd:%d n:%z", c->number, &addr, c->fd, n); } } #endif log->data = NULL; log->handler = NULL; ls->handler(c); if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available -= n; } } while (ev->available); }
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { void *rv; char **senv, **env; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; ngx_shm_zone_t *shm_zone, *oshm_zone; ngx_list_part_t *part, *opart; ngx_open_file_t *file; ngx_listening_t *ls, *nls; ngx_core_conf_t *ccf, *old_ccf; ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; ngx_timezone_update(); /* force localtime update with a new timezone */ tp = ngx_timeofday(); tp->sec = 0; ngx_time_update(); log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } pool->log = log; cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); if (cycle == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->pool = pool; cycle->log = log; cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix); if (cycle->conf_prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->prefix.len = old_cycle->prefix.len; cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix); if (cycle->prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_file.len = old_cycle->conf_file.len; cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); if (cycle->conf_file.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data, old_cycle->conf_file.len + 1); cycle->conf_param.len = old_cycle->conf_param.len; cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param); if (cycle->conf_param.data == NULL) { ngx_destroy_pool(pool); return NULL; } n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10; cycle->paths.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); if (cycle->paths.elts == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->paths.nelts = 0; cycle->paths.size = sizeof(ngx_path_t *); cycle->paths.nalloc = n; cycle->paths.pool = pool; if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } if (old_cycle->open_files.part.nelts) { n = old_cycle->open_files.part.nelts; for (part = old_cycle->open_files.part.next; part; part = part->next) { n += part->nelts; } } else { n = 20; } if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } if (old_cycle->shared_memory.part.nelts) { n = old_cycle->shared_memory.part.nelts; for (part = old_cycle->shared_memory.part.next; part; part = part->next) { n += part->nelts; } } else { n = 1; } if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) != NGX_OK) { 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; ngx_queue_init(&cycle->reusable_connections_queue); cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *)); if (cycle->conf_ctx == NULL) { ngx_destroy_pool(pool); return NULL; } if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed"); ngx_destroy_pool(pool); return NULL; } /* on Linux gethostname() silently truncates name that does not fit */ hostname[NGX_MAXHOSTNAMELEN - 1] = '\0'; cycle->hostname.len = ngx_strlen(hostname); cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len); if (cycle->hostname.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->create_conf) { rv = module->create_conf(cycle); if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[ngx_modules[i]->index] = rv; } } senv = environ; ngx_memzero(&conf, sizeof(ngx_conf_t)); /* STUB: init array ? */ conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); if (conf.args == NULL) { ngx_destroy_pool(pool); return NULL; } conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (conf.temp_pool == NULL) { ngx_destroy_pool(pool); return NULL; } conf.ctx = cycle->conf_ctx; conf.cycle = cycle; conf.pool = pool; conf.log = log; conf.module_type = NGX_CORE_MODULE; conf.cmd_type = NGX_MAIN_CONF; #if 0 log->log_level = NGX_LOG_DEBUG_ALL; #endif if (ngx_conf_param(&conf) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_test_config && !ngx_quiet_mode) { ngx_log_stderr(0, "the configuration file %s syntax is ok", cycle->conf_file.data); } for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } module = ngx_modules[i]->ctx; if (module->init_conf) { if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) == NGX_CONF_ERROR) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } if (ngx_process == NGX_PROCESS_SIGNALLER) { return cycle; } ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } } else if (!ngx_is_init_cycle(old_cycle)) { /* * we do not create the pid file in the first ngx_init_cycle() call * because we need to write the demonized process pid */ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (ccf->pid.len != old_ccf->pid.len || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0) { /* new pid file name */ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } ngx_delete_pidfile(old_cycle); } } if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) { goto failed; } if (ngx_create_paths(cycle, ccf->user) != NGX_OK) { goto failed; } if (ngx_log_open_default(cycle) != NGX_OK) { goto failed; } /* open the new files */ part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].name.len == 0) { continue; } file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0, "log: %p %d \"%s\"", &file[i], 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); goto failed; } #if !(NGX_WIN32) if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", file[i].name.data); goto failed; } #endif } cycle->log = &cycle->new_log; pool->log = &cycle->new_log; /* create shared memory */ part = &cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", &shm_zone[i].shm.name); goto failed; } shm_zone[i].shm.log = cycle->log; opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (n = 0; /* void */ ; n++) { if (n >= opart->nelts) { if (opart->next == NULL) { break; } opart = opart->next; oshm_zone = opart->elts; n = 0; } if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } if (ngx_strncmp(shm_zone[i].shm.name.data, oshm_zone[n].shm.name.data, shm_zone[i].shm.name.len) != 0) { continue; } if (shm_zone[i].tag == oshm_zone[n].tag && shm_zone[i].shm.size == oshm_zone[n].shm.size && !shm_zone[i].noreuse) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr; #if (NGX_WIN32) shm_zone[i].shm.handle = oshm_zone[n].shm.handle; #endif if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) { goto failed; } goto shm_zone_found; } ngx_shm_free(&oshm_zone[n].shm); break; } if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) { goto failed; } if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) { goto failed; } if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) { goto failed; } shm_zone_found: continue; } /* handle the listening sockets */ 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; } if (ls[i].remain) { continue; } if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen, ls[i].sockaddr, ls[i].socklen, 1) == NGX_OK) { nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1; if (ls[i].backlog != nls[n].backlog) { nls[n].listen = 1; } #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) /* * FreeBSD, except the most recent versions, * could not remove accept filter */ nls[n].deferred_accept = ls[i].deferred_accept; if (ls[i].accept_filter && nls[n].accept_filter) { if (ngx_strcmp(ls[i].accept_filter, nls[n].accept_filter) != 0) { nls[n].delete_deferred = 1; nls[n].add_deferred = 1; } } else if (ls[i].accept_filter) { nls[n].delete_deferred = 1; } else if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_REUSEPORT) if (nls[n].reuseport && !ls[i].reuseport) { nls[n].add_reuseport = 1; } #endif break; } } if (nls[n].fd == (ngx_socket_t) - 1) { nls[n].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif } } } else { ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (ls[i].accept_filter) { ls[i].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept) { ls[i].add_deferred = 1; } #endif } } if (ngx_open_listening_sockets(cycle) != NGX_OK) { goto failed; } if (!ngx_test_config) { ngx_configure_listening_sockets(cycle); } /* commit the new cycle configuration */ if (!ngx_use_stderr) { (void) ngx_log_redirect_stderr(cycle); } 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_OK) { /* fatal */ exit(1); } } } /* close and delete stuff that lefts from an old cycle */ /* free the unnecessary shared memory */ opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (i = 0; /* void */ ; i++) { if (i >= opart->nelts) { if (opart->next == NULL) { goto old_shm_zone_done; } opart = opart->next; oshm_zone = opart->elts; i = 0; } part = &cycle->shared_memory.part; shm_zone = part->elts; for (n = 0; /* void */ ; n++) { if (n >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; n = 0; } if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len && ngx_strncmp(oshm_zone[i].shm.name.data, shm_zone[n].shm.name.data, oshm_zone[i].shm.name.len) == 0) { goto live_shm_zone; } } ngx_shm_free(&oshm_zone[i].shm); live_shm_zone: continue; } old_shm_zone_done: /* close the unnecessary listening sockets */ ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { if (ls[i].remain || ls[i].fd == (ngx_socket_t) - 1) { continue; } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " listening socket on %V failed", &ls[i].addr_text); } #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX) { u_char *name; name = ls[i].addr_text.data + sizeof("unix:") - 1; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "deleting socket %s", name); if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_delete_file_n " %s failed", name); } } #endif } /* close the unnecessary open files */ part = &old_cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { 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); } } ngx_destroy_pool(conf.temp_pool); if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { /* * perl_destruct() frees environ, if it is not the same as it was at * perl_construct() time, therefore we save the previous cycle * environment before ngx_conf_parse() where it will be changed. */ env = environ; environ = senv; ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; environ = env; 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, "could 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.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_array_push(&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; failed: if (!ngx_is_init_cycle(old_cycle)) { old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (old_ccf->environment) { environ = old_ccf->environment; } } /* rollback the new cycle configuration */ part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { 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 (ngx_test_config) { ngx_destroy_cycle_pools(&conf); return NULL; } ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].fd == (ngx_socket_t) - 1 || !ls[i].open) { continue; } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } } ngx_destroy_cycle_pools(&conf); return NULL; }
//读取token static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; off_t file_size; size_t len; ssize_t n, size; ngx_uint_t found, need_space, last_space, sharp_comment, variable; ngx_uint_t quoted, s_quoted, d_quoted, start_line; ngx_str_t *word; ngx_buf_t *b; found = 0; need_space = 0; last_space = 1; sharp_comment = 0; variable = 0; quoted = 0; s_quoted = 0; d_quoted = 0; cf->args->nelts = 0; b = cf->conf_file->buffer; //填满一个buffer缓冲区 start = b->pos; start_line = cf->conf_file->line; file_size = ngx_file_size(&cf->conf_file->file.info); //得到文件长度 for ( ;; ) { if (b->pos >= b->last) { if (cf->conf_file->file.offset >= file_size) { if (cf->args->nelts > 0) { if (cf->conf_file->file.fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of parameter, " "expecting \";\""); return NGX_ERROR; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, " "expecting \";\" or \"}\""); return NGX_ERROR; } return NGX_CONF_FILE_DONE; } len = b->pos - start; //已扫描的字符数 if (len == NGX_CONF_BUFFER) { //等于整个缓存时 cf->conf_file->line = start_line; if (d_quoted) { //置为1,表示当前处于双引号字符串后 ch = '"'; } else if (s_quoted) { ch = '\''; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long parameter \"%*s...\" started", 10, start); return NGX_ERROR; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "too long parameter, probably " "missing terminating \"%c\" character", ch); return NGX_ERROR; } if (len) { ngx_memmove(b->start, start, len); //将已扫描的字符移动到头部 } size = (ssize_t) (file_size - cf->conf_file->file.offset); //还没有读取的字符 if (size > b->end - (b->start + len)) { size = b->end - (b->start + len); } n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); //读取 if (n == NGX_ERROR) { return NGX_ERROR; } if (n != size) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_read_file_n " returned " "only %z bytes instead of %z", n, size); return NGX_ERROR; } b->pos = b->start + len; //pos指向未处理的字符的头部 b->last = b->pos + n; //指向未处理字符的尾部 start = b->start; } ch = *b->pos++; if (ch == LF) { cf->conf_file->line++; //加一行 if (sharp_comment) { sharp_comment = 0; } } if (sharp_comment) { continue; } if (quoted) { quoted = 0; continue; } if (need_space) { if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { last_space = 1; //前一个字符为空白字符(空格,回车、tab等) need_space = 0; continue; } if (ch == ';') { //;表示结束 return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } if (ch == ')') { last_space = 1; need_space = 0; } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%c\"", ch); return NGX_ERROR; } } if (last_space) { if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) { continue; } start = b->pos - 1; start_line = cf->conf_file->line; switch (ch) { case ';': case '{': if (cf->args->nelts == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"%c\"", ch); return NGX_ERROR; } if (ch == '{') { return NGX_CONF_BLOCK_START; //开始 } return NGX_OK; case '}': if (cf->args->nelts != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); return NGX_ERROR; } return NGX_CONF_BLOCK_DONE; case '#': sharp_comment = 1; continue; case '\\': quoted = 1; last_space = 0; continue; case '"': start++; d_quoted = 1; //双引号后面 last_space = 0; continue; case '\'': start++; s_quoted = 1; //单引号后面 last_space = 0; continue; default: last_space = 0; } } else { if (ch == '{' && variable) { continue; } variable = 0; if (ch == '\\') { quoted = 1; continue; } if (ch == '$') { variable = 1; continue; } if (d_quoted) { if (ch == '"') { d_quoted = 0; need_space = 1; found = 1; //找到一个 } } else if (s_quoted) { if (ch == '\'') { s_quoted = 0; need_space = 1; found = 1; //找到一个 } } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF || ch == ';' || ch == '{') { last_space = 1; found = 1; } if (found) { word = ngx_array_push(cf->args); //cf->args数组 if (word == NULL) { return NGX_ERROR; } word->data = ngx_pnalloc(cf->pool, b->pos - start + 1); if (word->data == NULL) { return NGX_ERROR; } for (dst = word->data, src = start, len = 0; src < b->pos - 1; len++) { if (*src == '\\') { switch (src[1]) { case '"': case '\'': case '\\': src++; break; case 't': *dst++ = '\t'; src += 2; continue; case 'r': *dst++ = '\r'; src += 2; continue; case 'n': *dst++ = '\n'; src += 2; continue; } } *dst++ = *src++; } *dst = '\0'; word->len = len; if (ch == ';') { return NGX_OK; } if (ch == '{') { return NGX_CONF_BLOCK_START; } found = 0; } } } }
// main()函数里调用,启动worker进程 // 监听信号 // 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 void ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; size_t size; ngx_int_t i; ngx_uint_t n, sigio; sigset_t set; struct itimerval itv; ngx_uint_t live; ngx_msec_t delay; ngx_listening_t *ls; ngx_core_conf_t *ccf; // 添加master进程关注的信号 sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigprocmask() failed"); } sigemptyset(&set); // static u_char master_process[] = "master process"; // 计算master进程的名字 size = sizeof(master_process); // 加上命令行参数,注意使用的是nginx拷贝后的参数 for (i = 0; i < ngx_argc; i++) { size += ngx_strlen(ngx_argv[i]) + 1; } // 分配名字的内存 title = ngx_pnalloc(cycle->pool, size); if (title == NULL) { /* fatal */ exit(2); } // 拷贝字符串 p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); for (i = 0; i < ngx_argc; i++) { *p++ = ' '; p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size); } // 设置进程名 ngx_setproctitle(title); // 取core模块配置 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程,数量由配置决定,即worker_processes指令 // #define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // cache进程 ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; //延时的计数器 sigio = 0; live = 1; //是否有存活的子进程 // master进程的无限循环,只处理信号 // 主要调用ngx_signal_worker_processes()发送信号 // ngx_start_worker_processes()产生新子进程 for ( ;; ) { // 延时等待子进程关闭,每次进入加倍等待 if (delay) { if (ngx_sigalrm) { sigio = 0; delay *= 2; //延时加倍 ngx_sigalrm = 0; } ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "termination cycle: %d", delay); itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 0; itv.it_value.tv_sec = delay / 1000; itv.it_value.tv_usec = (delay % 1000 ) * 1000; // 系统调用,设置发送SIGALRM的时间间隔 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); // 核心操作是sigsuspend,暂时挂起进程,不占用CPU,只有收到信号时才被唤醒 // 收到SIGALRM就检查子进程是否都已经处理完了 sigsuspend(&set); // 更新一下时间 ngx_time_update(); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up, sigio %i", sigio); // 子进程可能发生了意外结束 // 在os/unix/ngx_process.c ngx_signal_handler()里设置 if (ngx_reap) { ngx_reap = 0; ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children"); // 重新产生子进程 live = ngx_reap_children(cycle); } // 无存活子进程且收到stop/quit信号 if (!live && (ngx_terminate || ngx_quit)) { // 删除pid,模块清理,关闭监听端口 // 内部直接exit(0)退出 ngx_master_process_exit(cycle); } // 收到了-s stop,停止进程 if (ngx_terminate) { // 延时等待子进程关闭 if (delay == 0) { delay = 50; } if (sigio) { sigio--; continue; } sigio = ccf->worker_processes + 2 /* cache processes */; if (delay > 1000) { // 超时太多,直接发送SIGKILL杀死进程 // master进程调用,遍历ngx_processes数组,用kill发送信号 ngx_signal_worker_processes(cycle, SIGKILL); } else { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_terminate ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } // 等待SIGALRM信号,检查子进程是否都结束 continue; } // 收到了-s quit,关闭监听端口后再停止进程(优雅关闭) if (ngx_quit) { // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_quit ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); // 关闭所有监听端口 ls = cycle->listening.elts; for (n = 0; n < cycle->listening.nelts; n++) { if (ngx_close_socket(ls[n].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[n].addr_text); } } cycle->listening.nelts = 0; continue; } // 收到了-s reload重新配置 if (ngx_reconfigure) { ngx_reconfigure = 0; // 启动新的nginx二进制 if (ngx_new_binary) { // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; } ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); // nginx可执行程序不变,以当前cycle重新初始化 cycle = ngx_init_cycle(cycle); if (cycle == NULL) { cycle = (ngx_cycle_t *) ngx_cycle; continue; } ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_JUST_RESPAWN -2 // 这样新启动的进程不会发送shutdown信号 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); /* allow new processes to start */ // 阻塞等待100毫秒 ngx_msleep(100); // 设置进程存活标志 live = 1; // 关闭原来的worker进程 // 新启动的进程不会发送shutdown信号 // master进程调用,遍历ngx_processes数组,用kill发送信号 // 走到worker进程的ngx_signal_handler() // 然后再是ngx_worker_process_cycle()的ngx_quit ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) { ngx_restart = 0; // 启动worker进程,数量由配置决定,即worker_processes指令 // 调用时传递的是#define NGX_PROCESS_RESPAWN -3 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); // 设置进程存活标志 live = 1; } if (ngx_reopen) { ngx_reopen = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); ngx_reopen_files(cycle, ccf->user); ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) { ngx_change_binary = 0; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary"); ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); } if (ngx_noaccept) { ngx_noaccept = 0; ngx_noaccepting = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } //master进程无限循环结束 }
//当有新连接后,会调用读ngx_event_t结构read的handler回调,监听socket会设置为这个函数。 //工作进程初始化的时候会调用ngx_event_process_init模块初始化函数设置为ngx_event_accept,当做accept钩子 //有新连接的时候会调用这里进行accept. //这里会将新连接放入epoll,监听可读可写事件,然后调用ngx_http_init_connection void ngx_event_accept(ngx_event_t *ev) { socklen_t socklen; ngx_err_t err; ngx_log_t *log; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; u_char sa[NGX_SOCKADDRLEN]; ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module);//先得到ngx_events_module,然后再得到里面的core模块 if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { ev->available = 1; } else if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept;//一次尽量接完,默认为0的 } lc = ev->data;//得到这个事件所属的连接 ls = lc->listening;//从而得到这个连接所指的listening 结构 ev->ready = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,"accept on %V, ready: %d", &ls->addr_text, ev->available); do {//这个连接有可读事件了,那可能可以读很多了,所以得有循环 socklen = NGX_SOCKADDRLEN; s = accept(lc->fd, (struct sockaddr *) sa, &socklen);//接一个新连接 if (s == -1) {//失败 err = ngx_socket_errno; if (err == NGX_EAGAIN) {//没有了这回 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, "accept() not ready"); return; } ngx_log_error((ngx_uint_t) ((err == NGX_ECONNABORTED) ? NGX_LOG_ERR : NGX_LOG_ALERT), ev->log, err, "accept() failed"); if (err == NGX_ECONNABORTED) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--;//kqueue的话不能接多个 } if (ev->available) { continue; } } return; } //accept成功 #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; //当已使用的连接数占到在nginx.conf里配置的worker_connections总数的7/8以上时,ngx_accept_disabled为大于0, //此后在主循环里面就不会再进行accept,而是递减1,这样相当于让我这个进程丢掉一点accept的机会吧。 //不过这个只在accept_mutex on 配置打开时才有效,否则的话是默认会不断监听的 c = ngx_get_connection(s, ev->log);//拿到一个空闲的连接 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"); } return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); //为这个连接新建一个pool,这样那个连接关闭后,这个内存池也可以释放了,这样大大减少内存泄露 if (c->pool == NULL) {//内存申请失败 ngx_close_accepted_connection(c); return; } c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(c->sockaddr, sa, socklen); 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_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " failed"); ngx_close_accepted_connection(c); return; } } } else {//设置为非阻塞的 if (!(ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT))) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " failed"); ngx_close_accepted_connection(c); return; } } } *log = ls->log; c->recv = ngx_recv;//k ngx_unix_recv ,其实还有ngx_ssl_recv c->send = ngx_send;//k ngx_unix_send , 其实还有ngx_ssl_write c->recv_chain = ngx_recv_chain;//k ngx_readv_chain c->send_chain = ngx_send_chain;//k ngx_writev_chain /*ngx_io = ngx_os_io ;//相当于这个IO是跟os相关的。 ngx_os_io_t ngx_os_io = { ngx_unix_recv, ngx_readv_chain, ngx_udp_unix_recv, ngx_unix_send, ngx_writev_chain, 0 };*/ c->log = log; c->pool->log = log; c->socklen = socklen; c->listening = ls;//刚申请的连接,回指一下这个连接所属的listening结构。指向我是从哪个listenSOCK accept出来的 c->local_sockaddr = ls->sockaddr; c->unexpected_eof = 1; #if (NGX_HAVE_UNIX_DOMAIN) if (c->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; } #endif rev = c->read;//这个新连接的读写事件 wev = c->write; wev->ready = 1;// 写事件,表示已经accept了 ? if (ngx_event_flags & (NGX_USE_AIO_EVENT|NGX_USE_RTSIG_EVENT)) { /* rtsig, aio, iocp */ rev->ready = 1; } if (ev->deferred_accept) { //如果采用deferred模式,内核在三次握手建立连接后,不会立即通知程序监听连接可读,而是等待到第一个可读数据包才通知,因此,此时是有可读事件的 rev->ready = 1;//这回可以读的 } rev->log = log; wev->log = log; /* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif #if (NGX_THREADS) rev->lock = &c->lock;//读写事件锁等于连接上的锁,对于多线程 wev->lock = &c->lock; rev->own_lock = &c->lock; wev->own_lock = &c->lock; #endif if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; } } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, "*%d accept: %V fd:%d", c->number, &c->addr_text, s); if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) {//现在加入了,但还没设置回调呢,不过没事,反正单进程,不会有事的。待会就加 //如果使用epoll,我喜欢.ngx_epoll_add_connection 采用边缘触发,注册EPOLLIN|EPOLLOUT|EPOLLET ngx_close_accepted_connection(c); return; } } log->data = NULL; log->handler = NULL; //注意,这个链接的读写事件回调句柄暂时还没有设置,为什么呢? 因为此处是通用的, //我只负责接受连接,加入epoll,具体句柄,看具体的类型了,是http还是ftp还是https啥的。具体的就得看这个listen sock是用于什么了,比如http,ftp啥的。 //比如说: 接收一个连接后,应该怎么办呢,应该进行对应的初始化。那怎么初始化? 解析时碰到什么,就怎么初始化吧 ls->handler(c);//指向ngx_http_init_connection,最开头是在ngx_http_commands -> ngx_http_block设置的 // ngx_http_block 里面调用了 ngx_http_optimize_servers ,这个函数对listening和connection相关的变量进行了初始化和调优, //并最终在 ngx_http_add_listening (被ngx_http_init_listening调用) 中注册了listening 的 handler 为 ngx_http_init_connection if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } } while (ev->available);//一次可以接多个,直到没有可读的了 }
ngx_int_t ngx_rtmp_process_request_uri(ngx_rtmp_session_t *s) { ngx_rtmp_core_srv_conf_t *cscf; if (s->args_start) { s->uri.len = s->args_start - 1 - s->uri_start; } else { s->uri.len = s->uri_end - s->uri_start; } if (s->complex_uri || s->quoted_uri) { s->uri.data = ngx_pnalloc(s->connection->pool, s->uri.len + 1); if (s->uri.data == NULL) { return NGX_ERROR; } cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); if (ngx_rtmp_parse_complex_uri(s, cscf->merge_slashes) != NGX_OK) { s->uri.len = 0; ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "client sent invalid request"); return NGX_ERROR; } } else { s->uri.data = s->uri_start; } s->unparsed_uri.len = s->uri_end - s->uri_start; s->unparsed_uri.data = s->uri_start; s->valid_unparsed_uri = s->space_in_uri ? 0 : 1; if (s->args_start && s->uri_end > s->args_start) { s->args.len = s->uri_end - s->args_start; s->args.data = s->args_start; } #if (NGX_WIN32) { u_char *p, *last; p = s->uri.data; last = s->uri.data + s->uri.len; while (p < last) { if (*p++ == ':') { /* * this check covers "::$data", "::$index_allocation" and * ":$i30:$index_allocation" */ if (p < last && *p == '$') { ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "client sent unsafe win32 URI"); return NGX_ERROR; } } } p = s->uri.data + s->uri.len - 1; while (p > s->uri.data) { if (*p == ' ') { p--; continue; } if (*p == '.') { p--; continue; } break; } if (p != s->uri.data + s->uri.len - 1) { s->uri.len = p + 1 - s->uri.data; } } #endif ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "rtmp uri: \"%V\"", &s->uri); ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, "rtmp args: \"%V\"", &s->args); return NGX_OK; }
static ngx_inline ngx_int_t ngx_http_modsecurity_load_request(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; request_rec *req; size_t root; ngx_str_t path; ngx_uint_t port; struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; #endif ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity); req = ctx->req; /* request line */ req->method = (char *)ngx_pstrdup0(r->pool, &r->method_name); /* TODO: how to use ap_method_number_of ? * req->method_number = ap_method_number_of(req->method); */ req->method_number = ngx_http_modsecurity_method_number(r->method); /* ngx_http_map_uri_to_path() allocates memory for terminating '\0' */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { return NGX_ERROR; } req->filename = (char *) path.data; req->path_info = req->filename; req->args = (char *)ngx_pstrdup0(r->pool, &r->args); req->proto_num = r->http_major *1000 + r->http_minor; req->protocol = (char *)ngx_pstrdup0(r->pool, &r->http_protocol); req->request_time = apr_time_make(r->start_sec, r->start_msec); req->the_request = (char *)ngx_pstrdup0(r->pool, &r->request_line); req->unparsed_uri = (char *)ngx_pstrdup0(r->pool, &r->unparsed_uri); req->uri = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.scheme = "http"; #if (NGX_HTTP_SSL) if (r->connection->ssl) { req->parsed_uri.scheme = "https"; } #endif req->parsed_uri.path = (char *)ngx_pstrdup0(r->pool, &r->uri); req->parsed_uri.is_initialized = 1; switch (r->connection->local_sockaddr->sa_family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; port = ntohs(sin6->sin6_port); break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: port = 0; break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->local_sockaddr; port = ntohs(sin->sin_port); break; } req->parsed_uri.port = port; req->parsed_uri.port_str = ngx_pnalloc(r->pool, sizeof("65535")); (void) ngx_sprintf((u_char *)req->parsed_uri.port_str, "%ui%c", port, '\0'); req->parsed_uri.query = r->args.len ? req->args : NULL; req->parsed_uri.dns_looked_up = 0; req->parsed_uri.dns_resolved = 0; // req->parsed_uri.password = (char *)ngx_pstrdup0(r->pool, &r->headers_in.passwd); // req->parsed_uri.user = (char *)ngx_pstrdup0(r->pool, &r->headers_in.user); req->parsed_uri.fragment = (char *)ngx_pstrdup0(r->pool, &r->exten); req->hostname = (char *)ngx_pstrdup0(r->pool, (ngx_str_t *)&ngx_cycle->hostname); req->header_only = r->header_only ? r->header_only : (r->method == NGX_HTTP_HEAD); return NGX_OK; }
//这里的event是在ngx_event_process_init中从连接池中获取的 ngx_connection_t中的->read读事件 //accept是在ngx_event_process_init(但进程或者不配置负载均衡的时候)或者(多进程,配置负载均衡)的时候把accept事件添加到epoll中 void //该形参中的ngx_connection_t(ngx_event_t)是为accept事件连接准备的空间,当accept返回成功后,会重新获取一个ngx_connection_t(ngx_event_t)用来读写该连接 ngx_event_accept(ngx_event_t *ev) //在ngx_process_events_and_timers中执行 { //一个accept事件对应一个ev,如当前一次有4个客户端accept,应该对应4个ev事件,一次来多个accept的处理在下面的do {}while中实现 socklen_t socklen; ngx_err_t err; ngx_log_t *log; ngx_uint_t level; ngx_socket_t s; //如果是文件异步i/o中的ngx_event_aio_t,则它来自ngx_event_aio_t->ngx_event_t(只有读),如果是网络事件中的event,则为ngx_connection_s中的event(包括读和写) ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; u_char sa[NGX_SOCKADDRLEN]; #if (NGX_HAVE_ACCEPT4) static ngx_uint_t use_accept4 = 1; #endif if (ev->timedout) { if (ngx_enable_accept_events((ngx_cycle_t *) ngx_cycle) != NGX_OK) { return; } ev->timedout = 0; } ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); if (!(ngx_event_flags & NGX_USE_KQUEUE_EVENT)) { ev->available = ecf->multi_accept; } 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->addr_text, ev->available); do { socklen = NGX_SOCKADDRLEN; #if (NGX_HAVE_ACCEPT4) //ngx_close_socket可以关闭套接字 if (use_accept4) { s = accept4(lc->fd, (struct sockaddr *) sa, &socklen, SOCK_NONBLOCK); } else { s = accept(lc->fd, (struct sockaddr *) sa, &socklen); } #else /* 针对非阻塞I/O执行的系统调用则总是立即返回,而不管事件足否已经发生。如果事件没有眭即发生,这些系统调用就 返回—1.和出错的情况一样。此时我们必须根据errno来区分这两种情况。对accept、send和recv而言,事件未发牛时errno 通常被设置成EAGAIN(意为“再来一次”)或者EWOULDBLOCK(意为“期待阻塞”):对conncct而言,errno则被 设置成EINPROGRESS(意为“在处理中")。 */ s = accept(lc->fd, (struct sockaddr *) sa, &socklen); #endif if (s == (ngx_socket_t) -1) { err = ngx_socket_errno; if (err == NGX_EAGAIN) { //如果event{}开启multi_accept,则在accept完该listen ip:port对应的ip和端口连接后,会通过这里返回 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, err, "accept() not ready"); return; } level = NGX_LOG_ALERT; if (err == NGX_ECONNABORTED) { level = NGX_LOG_ERR; } else if (err == NGX_EMFILE || err == NGX_ENFILE) { level = NGX_LOG_CRIT; } #if (NGX_HAVE_ACCEPT4) ngx_log_error(level, ev->log, err, use_accept4 ? "accept4() failed" : "accept() failed"); if (use_accept4 && err == NGX_ENOSYS) { use_accept4 = 0; ngx_inherited_nonblocking = 0; continue; } #else ngx_log_error(level, ev->log, err, "accept() failed"); #endif if (err == NGX_ECONNABORTED) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } if (ev->available) { continue; } } if (err == NGX_EMFILE || err == NGX_ENFILE) { if (ngx_disable_accept_events((ngx_cycle_t *) ngx_cycle, 1) != NGX_OK) { return; } if (ngx_use_accept_mutex) { if (ngx_accept_mutex_held) { ngx_shmtx_unlock(&ngx_accept_mutex); ngx_accept_mutex_held = 0; } //当前进程连接accpet失败,则可以暂时设置为1,下次来的时候由其他进程竞争accpet锁,下下次该进程继续竞争该accept,因为在下次的时候ngx_process_events_and_timers //ngx_accept_disabled = 1; 减去1后为0,可以继续竞争 ngx_accept_disabled = 1; } else { ////如果是不需要实现负载均衡,则扫尾延时下继续在ngx_process_events_and_timers中accept ngx_add_timer(ev, ecf->accept_mutex_delay, NGX_FUNC_LINE); } } return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_accepted, 1); #endif //设置负载均衡阀值 ngx_accept_disabled = ngx_cycle->connection_n / 8 - ngx_cycle->free_connection_n; //判断可用连接的数目和总数目的八分之一大小,如果可用的小于八分之一,为正 //在服务器端accept客户端连接成功(ngx_event_accept)后,会通过ngx_get_connection从连接池获取一个ngx_connection_t结构,也就是每个客户端连接对于一个ngx_connection_t结构, //并且为其分配一个ngx_http_connection_t结构,ngx_connection_t->data = ngx_http_connection_t,见ngx_http_init_connection //从连接池中获取一个空闲ngx_connection_t,用于客户端连接建立成功后向该连接读写数据,函数形参中的ngx_event_t对应的是为accept事件对应的 //ngx_connection_t中对应的event c = ngx_get_connection(s, ev->log); //ngx_get_connection中c->fd = s; //注意,这里的ngx_connection_t是从连接池中从新获取的,和ngx_epoll_process_events中的ngx_connection_t是两个不同的。 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"); } return; } #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif c->pool = ngx_create_pool(ls->pool_size, ev->log); if (c->pool == NULL) { ngx_close_accepted_connection(c); return; } c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); return; } ngx_memcpy(c->sockaddr, sa, socklen); log = ngx_palloc(c->pool, sizeof(ngx_log_t)); if (log == NULL) { ngx_close_accepted_connection(c); return; } /* set a blocking mode for iocp and non-blocking mode for others */ if (ngx_inherited_nonblocking) { if (ngx_event_flags & NGX_USE_IOCP_EVENT) { if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_blocking_n " failed"); ngx_close_accepted_connection(c); return; } } } else { if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ngx_nonblocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, ngx_nonblocking_n " failed"); ngx_close_accepted_connection(c); return; } } } *log = ls->log; c->recv = ngx_recv; c->send = ngx_send; c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; c->log = log; c->pool->log = log; c->socklen = socklen; c->listening = ls; c->local_sockaddr = ls->sockaddr; c->local_socklen = ls->socklen; c->unexpected_eof = 1; #if (NGX_HAVE_UNIX_DOMAIN) if (c->sockaddr->sa_family == AF_UNIX) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; #if (NGX_SOLARIS) /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ c->sendfile = 0; #endif } #endif //注意,这里的ngx_connection_t是从连接池中从新获取的,和ngx_epoll_process_events中的ngx_connection_t是两个不同的。 rev = c->read; wev = c->write; wev->ready = 1; if (ngx_event_flags & NGX_USE_IOCP_EVENT) { rev->ready = 1; } if (ev->deferred_accept) { rev->ready = 1; #if (NGX_HAVE_KQUEUE) rev->available = 1; #endif } rev->log = log; wev->log = log; /* * TODO: MT: - ngx_atomic_fetch_add() * or protection by critical section or light mutex * * TODO: MP: - allocated in a shared memory * - ngx_atomic_fetch_add() * or protection by critical section or light mutex */ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1); #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_handled, 1); #endif if (ls->addr_ntop) { c->addr_text.data = ngx_pnalloc(c->pool, ls->addr_text_max_len); if (c->addr_text.data == NULL) { ngx_close_accepted_connection(c); return; } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->socklen, c->addr_text.data, ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; } } #if (NGX_DEBUG) { ngx_str_t addr; struct sockaddr_in *sin; ngx_cidr_t *cidr; ngx_uint_t i; u_char text[NGX_SOCKADDR_STRLEN]; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; ngx_uint_t n; #endif cidr = ecf->debug_connection.elts; for (i = 0; i < ecf->debug_connection.nelts; i++) { if (cidr[i].family != (ngx_uint_t) c->sockaddr->sa_family) { goto next; } switch (cidr[i].family) { #if (NGX_HAVE_INET6) case AF_INET6: sin6 = (struct sockaddr_in6 *) c->sockaddr; for (n = 0; n < 16; n++) { if ((sin6->sin6_addr.s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n]) != cidr[i].u.in6.addr.s6_addr[n]) { goto next; } } break; #endif #if (NGX_HAVE_UNIX_DOMAIN) case AF_UNIX: break; #endif default: /* AF_INET */ sin = (struct sockaddr_in *) c->sockaddr; if ((sin->sin_addr.s_addr & cidr[i].u.in.mask) != cidr[i].u.in.addr) { goto next; } break; } log->log_level = NGX_LOG_DEBUG_CONNECTION|NGX_LOG_DEBUG_ALL; break; next: continue; } if (log->log_level & NGX_LOG_DEBUG_EVENT) { addr.data = text; addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0, "*%uA accept: %V fd:%d", c->number, &addr, s); } } #endif if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { //如果是epoll,不会走到这里面去 if (ngx_add_conn(c) == NGX_ERROR) { ngx_close_accepted_connection(c); return; } } log->data = NULL; log->handler = NULL; ls->handler(c);//ngx_http_init_connection if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ev->available--; } } while (ev->available); //一次性读取所有当前的accept,直到accept返回NGX_EAGAIN,然后退出 }
/* 加载配置文件,并回调create_conf,init_conf, init_module等; 初始化各个配置,并打开监听端口,设置优化选项; */ ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) {//整个程序的主要初始化,配置加载,解析,各个模块的初始化回调函数,指令的set回调函数调用,监听端口打开,共享内存申请等等都在这里. void *rv; char **senv, **env; ngx_uint_t i, n; ngx_log_t *log; ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; ngx_shm_zone_t *shm_zone, *oshm_zone; ngx_list_part_t *part, *opart; ngx_open_file_t *file; ngx_listening_t *ls, *nls; ngx_core_conf_t *ccf, *old_ccf; ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; ngx_timezone_update(); /* force localtime update with a new timezone */ tp = ngx_timeofday();//k : ngx_cached_time tp->sec = 0;//秒设置为0 ngx_time_update();//迫使当前的缓存时间更新。 log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (pool == NULL) { return NULL; } pool->log = log; cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));//下一个过程吗 if (cycle == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->pool = pool;//cycle也是包含在pool里面的! ,也就是,释放了cycle->pool后,cycle也释放了 cycle->log = log; cycle->new_log.log_level = NGX_LOG_ERR; cycle->old_cycle = old_cycle; //下面拷贝一下旧的配置路径什么的,参数等到新的cycle cycle->conf_prefix.len = old_cycle->conf_prefix.len; cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix); if (cycle->conf_prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->prefix.len = old_cycle->prefix.len; cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix); if (cycle->prefix.data == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_file.len = old_cycle->conf_file.len; cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1); if (cycle->conf_file.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data, old_cycle->conf_file.len + 1); cycle->conf_param.len = old_cycle->conf_param.len; cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param); if (cycle->conf_param.data == NULL) { ngx_destroy_pool(pool); return NULL; } //干嘛的? n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); if (cycle->pathes.elts == NULL) { 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; if (old_cycle->open_files.part.nelts) { n = old_cycle->open_files.part.nelts; for (part = old_cycle->open_files.part.next; part; part = part->next) { n += part->nelts; } } else { n = 20; } if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)) != NGX_OK) { ngx_destroy_pool(pool); return NULL; } //拷贝共享内存 if (old_cycle->shared_memory.part.nelts) { n = old_cycle->shared_memory.part.nelts; for (part = old_cycle->shared_memory.part.next; part; part = part->next) { n += part->nelts; } } else { n = 1; } if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) != NGX_OK) { 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 (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed"); ngx_destroy_pool(pool); return NULL; } /* on Linux gethostname() silently truncates name that does not fit */ hostname[NGX_MAXHOSTNAMELEN - 1] = '\0'; cycle->hostname.len = ngx_strlen(hostname); cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len); if (cycle->hostname.data == NULL) { ngx_destroy_pool(pool); return NULL; } ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); //k:for core modules. for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } //对于核心模块 module = ngx_modules[i]->ctx; if (module->create_conf) {//如果核心模块设置了create_conf回调,则调用它们 rv = module->create_conf(cycle); if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[ ngx_modules[i]->index ] = rv;//帮模块们保存create_conf返回的数据。后续可以方便取到 } } senv = environ;//保留老的environ,这个环境变量已经被我们拷贝到了新地址的 ngx_memzero(&conf, sizeof(ngx_conf_t)); /* STUB: init array ? */ conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); if (conf.args == NULL) { ngx_destroy_pool(pool); return NULL; } conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); if (conf.temp_pool == NULL) { ngx_destroy_pool(pool); return NULL; } //切换到新的配置 conf.ctx = cycle->conf_ctx; conf.cycle = cycle; conf.pool = pool; conf.log = log; conf.module_type = NGX_CORE_MODULE; conf.cmd_type = NGX_MAIN_CONF; #if 0 log->log_level = NGX_LOG_DEBUG_ALL; #endif if (ngx_conf_param(&conf) != NGX_CONF_OK) {//调用ngx_conf_parse解析全局指令,貌似是做参数准备的。 environ = senv;//还原老的environ,因为perl会改变它 ngx_destroy_cycle_pools(&conf); return NULL; } //解析配置文件,调用各个配置文件的set函数等。 if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_test_config && !ngx_quiet_mode) {//这就是经典的那个-t参数啦 ngx_log_stderr(0, "the configuration file %s syntax is ok", cycle->conf_file.data); } for (i = 0; ngx_modules[i]; i++) { //刚才各个配置指令已经调用了其set函数的。下面调用一下每个模块的init_conf,也就是每个模块的各个指令已经设置,现在开始模块本身了。 if (ngx_modules[i]->type != NGX_CORE_MODULE) { continue; } //对于NGX_CORE_MODULE,调用它他们的init_conf回调 module = ngx_modules[i]->ctx;//得到模块初始化设置的数据,然后调用其init_conf if (module->init_conf) { if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])== NGX_CONF_ERROR){ //第二个参数是在create_conf回调返回的东西 environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } if (ngx_process == NGX_PROCESS_SIGNALLER) { return cycle;//如果是加-s reload等启动的,这里可以返回了。服务需要重启啥的,不是全新启动。在这里设置的ngx_get_options } // 最核心的配置 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);//k conf_ctx[module.index] if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } } else if (!ngx_is_init_cycle(old_cycle)) {//第一次调用,old_cycle的配置相关的为空,第二次才是非空的。也就是下面的注释介绍的 /* * we do not create the pid file in the first ngx_init_cycle() call * because we need to write the demonized process pid */ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (ccf->pid.len != old_ccf->pid.len || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0) { /* new pid file name */ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { goto failed; } ngx_delete_pidfile(old_cycle);//删除旧的,这是啥原因,比如配置重新加载吗,文件变了啥的 } } //就打开文件,关闭,然后删除之 if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) { goto failed; } //创建这些目录,并设置权限啥的 if (ngx_create_pathes(cycle, ccf->user) != NGX_OK) { goto failed; } if (cycle->new_log.file == NULL) {//找到"logs/error.log"的ngx_open_file_t*结构,不open打开 cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);//"logs/error.log" if (cycle->new_log.file == NULL) { goto failed; } } /* open the new files */ part = &cycle->open_files.part; file = part->elts; //一个个打开这些文件,APPEND模式打开 for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].name.len == 0) { continue; } //真正打开这些文件,append模式 file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0, "log: %p %d \"%s\"", &file[i], 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); goto failed; } #if !(NGX_WIN32) // 这里设置为FD_CLOEXEC表示当程序执行exec函数时本fd将被系统自动关闭,表示不传递给exec创建的新进程。close-on-exec if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fcntl(FD_CLOEXEC) \"%s\" failed", file[i].name.data); goto failed; } #endif } cycle->log = &cycle->new_log; pool->log = &cycle->new_log; /* create shared memory */ part = &cycle->shared_memory.part; shm_zone = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; i = 0; } if (shm_zone[i].shm.size == 0) { ngx_log_error(NGX_LOG_EMERG, log, 0, "zero size shared memory zone \"%V\"", &shm_zone[i].shm.name); goto failed; } if (shm_zone[i].init == NULL) { /* unused shared zone */ continue; } shm_zone[i].shm.log = cycle->log; opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (n = 0; /* void */ ; n++) { if (n >= opart->nelts) { if (opart->next == NULL) { break; } opart = opart->next; oshm_zone = opart->elts; n = 0; } if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { continue; } if (ngx_strncmp(shm_zone[i].shm.name.data, oshm_zone[n].shm.name.data, shm_zone[i].shm.name.len) != 0) { continue; } if (shm_zone[i].shm.size == oshm_zone[n].shm.size) { shm_zone[i].shm.addr = oshm_zone[n].shm.addr; if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data) != NGX_OK) { goto failed; } goto shm_zone_found; } ngx_shm_free(&oshm_zone[n].shm); break; } if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) { goto failed; } if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) { goto failed; } if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) { goto failed; } shm_zone_found: continue; } /* handle the listening sockets */ if (old_cycle->listening.nelts) {//如果设置了继承SOCK,就拷贝到cycle来 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; } if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) == NGX_OK) {//如果地址完全相同,那后面就不需要关闭,直接拷贝fd就行了 nls[n].fd = ls[i].fd; nls[n].previous = &ls[i]; ls[i].remain = 1; if (ls[n].backlog != nls[i].backlog) { nls[n].listen = 1; } #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) /* * FreeBSD, except the most recent versions, * could not remove accept filter */ nls[n].deferred_accept = ls[i].deferred_accept; if (ls[i].accept_filter && nls[n].accept_filter) { if (ngx_strcmp(ls[i].accept_filter, nls[n].accept_filter) != 0) { nls[n].delete_deferred = 1; nls[n].add_deferred = 1; } } else if (ls[i].accept_filter) { nls[n].delete_deferred = 1; } else if (nls[n].accept_filter) { nls[n].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[n].deferred_accept && !nls[n].deferred_accept) { nls[n].delete_deferred = 1; } else if (ls[i].deferred_accept != nls[n].deferred_accept) { nls[n].add_deferred = 1; } #endif break; } } if (nls[n].fd == -1) { nls[n].open = 1; } } } else { ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].open = 1; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) if (ls[i].accept_filter) { ls[i].add_deferred = 1; } #endif #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) if (ls[i].deferred_accept) { ls[i].add_deferred = 1; } #endif } } //下面一个个打开cycle->listening的listen的端口,并设置为listening端口 //这些监听端口的可读事件是在ngx_event_core_module模块中设置的,其进程初始化函数为ngx_event_process_init里面会放入epoll里面 if (ngx_open_listening_sockets(cycle) != NGX_OK) { goto failed; } if (!ngx_test_config) {//如果不是测试配置,设置一下各个优化选项,比如发送,接收缓冲区大小,TCP_DEFER_ACCEPT等 ngx_configure_listening_sockets(cycle); } /* commit the new cycle configuration */ if (!ngx_use_stderr && cycle->log->file->fd != ngx_stderr) { if (ngx_set_stderr(cycle->log->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_set_stderr_n " failed"); } } pool->log = cycle->log; for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_module) {//对所有模块,调用其init_module回调 if (ngx_modules[i]->init_module(cycle) != NGX_OK) { /* fatal */ exit(1); } } } /* close and delete stuff that lefts from an old cycle */ /* free the unnecessary shared memory */ opart = &old_cycle->shared_memory.part; oshm_zone = opart->elts; for (i = 0; /* void */ ; i++) { if (i >= opart->nelts) { if (opart->next == NULL) { goto old_shm_zone_done; } opart = opart->next; oshm_zone = opart->elts; i = 0; } part = &cycle->shared_memory.part; shm_zone = part->elts; for (n = 0; /* void */ ; n++) { if (n >= part->nelts) { if (part->next == NULL) { break; } part = part->next; shm_zone = part->elts; n = 0; } if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len && ngx_strncmp(oshm_zone[i].shm.name.data, shm_zone[n].shm.name.data, oshm_zone[i].shm.name.len) == 0){ goto live_shm_zone; } } ngx_shm_free(&oshm_zone[i].shm); live_shm_zone: continue; } old_shm_zone_done: /* close the unnecessary listening sockets */ ls = old_cycle->listening.elts; for (i = 0; i < old_cycle->listening.nelts; i++) { if (ls[i].remain || ls[i].fd == -1) { continue;//需要保留或者fd无效,不用删除,因为已经拷贝到cycle中了 } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,ngx_close_socket_n " listening socket on %V failed", &ls[i].addr_text); } #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX) { u_char *name; name = ls[i].addr_text.data + sizeof("unix:") - 1; ngx_log_error(NGX_LOG_WARN, cycle->log, 0, "deleting socket %s", name); if (ngx_delete_file(name) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, ngx_delete_file_n " %s failed", name); } } #endif } /* close the unnecessary open files */ part = &old_cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { 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); } } ngx_destroy_pool(conf.temp_pool); if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {//ngx_is_init_cycle第一次调用false //这是怎么进来的? /* * perl_destruct() frees environ, if it is not the same as it was at * perl_construct() time, therefore we save the previous cycle * environment before ngx_conf_parse() where it will be changed. */ env = environ; environ = senv;//还原之前保存的环境变量地址 ngx_destroy_pool(old_cycle->pool); cycle->old_cycle = NULL; environ = env; 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.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_array_push(&ngx_old_cycles); if (old == NULL) { exit(1); } *old = old_cycle; if (!ngx_cleaner_event.timer_set) {//如果还没有设置定时器,设置定时器,30秒后清除老的cycle? ngx_add_timer(&ngx_cleaner_event, 30000); ngx_cleaner_event.timer_set = 1;//标记此处已经设置过定时器了。 } return cycle; failed: if (!ngx_is_init_cycle(old_cycle)) { old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx, ngx_core_module); if (old_ccf->environment) { environ = old_ccf->environment; } } /* rollback the new cycle configuration */ part = &cycle->open_files.part; file = part->elts; for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { break; } part = part->next; file = part->elts; i = 0; } if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) { 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 (ngx_test_config) { ngx_destroy_cycle_pools(&conf); return NULL; } ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { if (ls[i].fd == -1 || !ls[i].open) { continue; } if (ngx_close_socket(ls[i].fd) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, ngx_close_socket_n " %V failed", &ls[i].addr_text); } } ngx_destroy_cycle_pools(&conf); return NULL; }
static ngx_int_t ngx_http_session_sticky_rewrite(ngx_http_request_t *r, ngx_table_elt_t *table) { u_char *p, *st, *en, *last, *start; ngx_http_ss_ctx_t *ctx; enum { pre_equal = 0, pre_value, value } state; ctx = ngx_http_get_module_ctx(r, ngx_http_upstream_session_sticky_module); p = ngx_strlcasestrn(table->value.data, table->value.data + table->value.len, ctx->sscf->cookie.data, ctx->sscf->cookie.len - 1); if (p == NULL) { return NGX_AGAIN; } st = p; start = table->value.data; last = table->value.data + table->value.len; state = 0; while (p < last) { switch (state) { case pre_equal: if (*p == '=') { state = pre_value; } else if (*p == ';') { goto success; } break; case pre_value: if (!is_space(*p)) { state = value; p--; } break; case value: if (*p == ';') { goto success; } break; default: break; } p++; } if (p >= last && (state == value || state == pre_equal)) { goto success; } return NGX_AGAIN; success: en = p; table->value.len = table->value.len - (en - st) + ctx->sscf->cookie.len + 1 /* '=' */ + ctx->sid.len; p = ngx_pnalloc(r->pool, table->value.len); if (p == NULL) { return NGX_ERROR; } table->value.data = p; p = ngx_cpymem(p, start, st - start); p = ngx_cpymem(p, ctx->sscf->cookie.data, ctx->sscf->cookie.len); *p++ = '='; p = ngx_cpymem(p, ctx->sid.data, ctx->sid.len); p = ngx_cpymem(p, en, last - en); return NGX_OK; }