static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) { u_char *name; size_t len; time_t wait; ngx_uint_t tries; ngx_path_t *path; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache forced expire"); path = cache->path; len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { return 10; } ngx_memcpy(name, path->name.data, path->name.len); wait = 10; tries = 20; ngx_shmtx_lock(&cache->shpool->mutex); for (q = ngx_queue_last(&cache->sh->queue); q != ngx_queue_sentinel(&cache->sh->queue); q = ngx_queue_prev(q)) { fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd", fcn->count, fcn->exists, fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); if (fcn->count == 0) { ngx_http_file_cache_delete(cache, q, name); wait = 0; } else { if (--tries) { continue; } wait = 1; } break; } ngx_shmtx_unlock(&cache->shpool->mutex); ngx_free(name); return wait; }
static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else { ngx_use_accept_mutex = 0; } #if (NGX_THREADS) ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); if (ngx_posted_events_mutex == NULL) { return NGX_ERROR; } #endif if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { exit(2); /* fatal */ } break; } #if !(NGX_WIN32) if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = ngx_timer_signal_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; #if (NGX_THREADS) rev[i].lock = &c[i].lock; rev[i].own_lock = &c[i].lock; #endif } cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; #if (NGX_THREADS) wev[i].lock = &c[i].lock; wev[i].own_lock = &c[i].lock; #endif } i = cycle->connection_n; next = NULL; do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer) { ngx_kqueue_conf_t *kcf; struct timespec ts; #if (NGX_HAVE_TIMER_EVENT) struct kevent kev; #endif kcf = ngx_event_get_conf(cycle->conf_ctx, ngx_kqueue_module); if (ngx_kqueue == -1) { ngx_kqueue = kqueue(); if (ngx_kqueue == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "kqueue() failed"); return NGX_ERROR; } #if (NGX_THREADS) list_mutex = ngx_mutex_init(cycle->log, 0); if (list_mutex == NULL) { return NGX_ERROR; } kevent_mutex = ngx_mutex_init(cycle->log, 0); if (kevent_mutex == NULL) { return NGX_ERROR; } #endif } if (max_changes < kcf->changes) { if (nchanges) { ts.tv_sec = 0; ts.tv_nsec = 0; if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "kevent() failed"); return NGX_ERROR; } nchanges = 0; } if (change_list0) { ngx_free(change_list0); } change_list0 = ngx_alloc(kcf->changes * sizeof(struct kevent), cycle->log); if (change_list0 == NULL) { return NGX_ERROR; } if (change_list1) { ngx_free(change_list1); } change_list1 = ngx_alloc(kcf->changes * sizeof(struct kevent), cycle->log); if (change_list1 == NULL) { return NGX_ERROR; } change_list = change_list0; } max_changes = kcf->changes; if (nevents < kcf->events) { if (event_list) { ngx_free(event_list); } event_list = ngx_alloc(kcf->events * sizeof(struct kevent), cycle->log); if (event_list == NULL) { return NGX_ERROR; } } ngx_event_flags = NGX_USE_ONESHOT_EVENT |NGX_USE_KQUEUE_EVENT |NGX_USE_VNODE_EVENT; #if (NGX_HAVE_TIMER_EVENT) if (timer) { kev.ident = 0; kev.filter = EVFILT_TIMER; kev.flags = EV_ADD|EV_ENABLE; kev.fflags = 0; kev.data = timer; kev.udata = 0; ts.tv_sec = 0; ts.tv_nsec = 0; if (kevent(ngx_kqueue, &kev, 1, NULL, 0, &ts) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "kevent(EVFILT_TIMER) failed"); return NGX_ERROR; } ngx_event_flags |= NGX_USE_TIMER_EVENT; } #endif #if (NGX_HAVE_CLEAR_EVENT) ngx_event_flags |= NGX_USE_CLEAR_EVENT; #else ngx_event_flags |= NGX_USE_LEVEL_EVENT; #endif #if (NGX_HAVE_LOWAT_EVENT) ngx_event_flags |= NGX_USE_LOWAT_EVENT; #endif nevents = kcf->events; ngx_io = ngx_os_io; ngx_event_actions = ngx_kqueue_module_ctx.actions; return NGX_OK; }
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)){ return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short)); if (test == NULL) { return NGX_ERROR; } bucket_size = hinit->bucket_size - sizeof(void *); start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size < hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } ngx_free(test); return NGX_ERROR; found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_short) names[n].key.len; ngx_strlow(elt->name, names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; #if 0 for (i = 0; i < size; i++) { ngx_str_t val; ngx_uint_t key; elt = buckets[i]; if (elt == NULL) { ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: NULL", i); continue; } while (elt->value) { val.len = elt->len; val.data = &elt->name[0]; key = hinit->key(val.data, val.len); ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %p \"%V\" %ui", i, elt, &val, key); elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } #endif return NGX_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { //第二个数为保存的配置文件路径的字符串,如/usr/local/nginx/conf/nginx.conf_file char *rv; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf; ngx_conf_file_t *prev, conf_file; enum { parse_file = 0, parse_block, parse_param } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { //指向一个配置文件路径字符串,需要函数ngx_conf_parse打开该文件并获取相关的文件信息 /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; cf->conf_file = &conf_file; if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = &buf; buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log); //内存 if (buf.start == NULL) { goto failed; } buf.pos = buf.start; //初始值 buf.last = buf.start; buf.end = buf.last + NGX_CONF_BUFFER; //4K,到末尾 buf.temporary = 1; cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; type = parse_file; //刚刚打开的新文件,包括include指令 } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { //说明此时仅解析了部分解析,当遇到复杂配置项,比如events,http等,此时解析的内容还是来自当前文件 type = parse_block; } else { //正要开始解析命令行参数配置项值,在对用户通过命令行-g参数输入的配置信息进行解析,如nginx -g 'daemon on' type = parse_param; } for ( ;; ) { rc = ngx_conf_read_token(cf); //读取token,每次读取一个buffer /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } if (rc == NGX_CONF_BLOCK_DONE) { //解析正常 if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_FILE_DONE) { if (type == parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_BLOCK_START) { if (type == parse_param) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ if (cf->handler) { //进行这些token转换为Nginx内控制变量的值,针对“text/html html htm shtml”等这样的配置项或geo模块里的“192.168.0.0/16 local”这样的不定配置项,进行特殊的处理 /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } if (rv == NGX_CONF_ERROR) { goto failed; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); goto failed; } rc = ngx_conf_handler(cf, rc); //配置转换 if (rc == NGX_ERROR) { goto failed; } } failed: rc = NGX_ERROR; done: if (filename) { if (cf->conf_file->buffer->start) { ngx_free(cf->conf_file->buffer->start); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", filename->data); return NGX_CONF_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) { BIO *bio; int len; u_char *p, *buf; OCSP_RESPONSE *response; ngx_ssl_stapling_t *staple; staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { return NGX_ERROR; } bio = BIO_new_file((char *) file->data, "r"); if (bio == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BIO_new_file(\"%s\") failed", file->data); return NGX_ERROR; } response = d2i_OCSP_RESPONSE_bio(bio, NULL); if (response == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "d2i_OCSP_RESPONSE_bio(\"%s\") failed", file->data); BIO_free(bio); return NGX_ERROR; } len = i2d_OCSP_RESPONSE(response, NULL); if (len <= 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "i2d_OCSP_RESPONSE(\"%s\") failed", file->data); goto failed; } buf = ngx_alloc(len, ssl->log); if (buf == NULL) { goto failed; } p = buf; len = i2d_OCSP_RESPONSE(response, &p); if (len <= 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "i2d_OCSP_RESPONSE(\"%s\") failed", file->data); ngx_free(buf); goto failed; } OCSP_RESPONSE_free(response); BIO_free(bio); staple->staple.data = buf; staple->staple.len = len; return NGX_OK; failed: OCSP_RESPONSE_free(response); BIO_free(bio); return NGX_ERROR; }
//这个函数的详细解析 //请参看:http://www.pagefault.info/?p=188 nginx的启动流程分析(一) // http://www.pagefault.info/?p=368 //第二个参数可以为空的,如果为空,则说明将要解析的是block中的内容或者param char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf; ngx_conf_file_t *prev, conf_file; enum { parse_file = 0, parse_block, parse_param } type; // 经过这个宏 #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { /* open configuration file */ // 打开配置文件 fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); // NGX_INVALID_FILE 为宏定义,值为-1 ,定义在/os/unix/ngx_files.h 中 if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; cf->conf_file = &conf_file; // 获取配置文件的stat信息,并存储到cf->conf_file->file.info这个stat结构体中 // ngx_fd_info 这个函数是fstat这个函数的宏包装。参考./os/unix/ngx_files.h if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = &buf; // 申请一个NGX_CONF_BUFFER大小的buffer,用于 ngx_conf_read_token() 函数解析配置文件 buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log); if (buf.start == NULL) { goto failed; } buf.pos = buf.start; buf.last = buf.start; buf.end = buf.last + NGX_CONF_BUFFER; buf.temporary = 1; // 保存配置文件的基本信息 cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; type = parse_file; } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; } else { type = parse_param; } //循环遍历每一行配置文件,读取配置内容 for ( ;; ) { //读入一个token,一般是一行 //读到的配置参数放到: (ngx_str_t*)(*((*cf).args)).elts rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } if (rc == NGX_CONF_BLOCK_DONE) { if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_FILE_DONE) { if (type == parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_BLOCK_START) { if (type == parse_param) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ //判断cf是否有handler回调,如果有的话,优先调用handler回调,如果没有,则会进入ngx_conf_handler进行一般处理 //特别说一下,http的模块使用handler是ngx_http_block,具体请看ngx_http.c if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ //使用handler处理 rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } if (rv == NGX_CONF_ERROR) { goto failed; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); goto failed; } //否则进入一般处理, 调用ngx_conf_handler对当前的token进行处理 // 参数中的rc 为ngx_read_conf_token的返回值 rc = ngx_conf_handler(cf, rc); if (rc == NGX_ERROR) { goto failed; } } //end for failed: rc = NGX_ERROR; done: //恢复现存、关闭已经打开的文件 //NGX_CONF_FILE_DONE 时必须要处理的部分 if (filename) { if (cf->conf_file->buffer->start) { ngx_free(cf->conf_file->buffer->start); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", filename->data); return NGX_CONF_ERROR; } cf->conf_file = prev; } // NGX_ERROR NGX_CONF_FILE_DONE NGX_CONF_BLOCK_DONE 时都需要处理的部分 if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
//在创建子进程的里面执行 ngx_worker_process_init static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); /* 当打开accept_mutex负载均衡锁,同时使用了master模式并且worker迸程数量大于1时,才正式确定了进程将使用accept_mutex负载均衡锁。 因此,即使我们在配置文件中指定打开accept_mutex锁,如果没有使用master模式或者worker进程数量等于1,进程在运行时还是不会使用 负载均衡锁(既然不存在多个进程去抢一个监听端口上的连接的情况,那么自然不需要均衡多个worker进程的负载)。 这时会将ngx_use_accept_mutex全局变量置为1,ngx_accept_mutex_held标志设为0,ngx_accept_mutex_delay则设为在配置文件中指定的最大延迟时间。 这3个变量的意义可参见9.8节中关于负载均衡锁的说明。 */ if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { ngx_use_accept_mutex = 1; ngx_accept_mutex_held = 0; ngx_accept_mutex_delay = ecf->accept_mutex_delay; } else { ngx_use_accept_mutex = 0; } #if (NGX_WIN32) /* * disable accept mutex on win32 as it may cause deadlock if * grabbed by a process which can't accept connections */ ngx_use_accept_mutex = 0; #endif ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_events); //初始化红黑树实现的定时器。关于定时器的实现细节可参见9.6节。 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } //在调用use配置项指定的事件模块中,在ngx_event_module_t接口下,ngx_event_actions_t中的init方法进行这个事件模块的初始化工作。 for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { //找到epoll或者select的module模块 continue; } module = ngx_modules[m]->ctx; if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { //执行epoll module中的ngx_epoll_init /* fatal */ exit(2); } break; /*跳出循环,只可能使用一个具体的事件模型*/ } #if !(NGX_WIN32) /* 如果nginx.conf配置文件中设置了timer_resolution酡置项,即表明需要控制时间精度,这时会调用setitimer方法,设置时间间隔 为timer_resolution毫秒来回调ngx_timer_signal_handler方法 */ if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; //设置定时器 /* 在ngx_event_ actions t的process_events方法中,每一个事件驱动模块都需要在ngx_event_timer_alarm为1时调 用ngx_time_update方法(参见9.7.1节)更新系统时间,在更新系统结束后需要将ngx_event_timer_alarm设为0。 */ ngx_memzero(&sa, sizeof(struct sigaction)); //每隔ngx_timer_resolution ms会超时执行handle sa.sa_handler = ngx_timer_signal_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } itv.it_interval.tv_sec = ngx_timer_resolution / 1000; itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; itv.it_value.tv_sec = ngx_timer_resolution / 1000; itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } /* 如果使用了epoll事件驱动模式,那么会为ngx_cycle_t结构体中的files成员预分配旬柄。 */ if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; //每个进程能够打开的最多文件数 cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; } cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; } i = cycle->connection_n; next = NULL; /* 接照序号,将上述3个数组相应的读/写事件设置到每一个ngx_connection_t连接对象中,同时把这些连接以ngx_connection_t中的data成员 作为next指针串联成链表,为下一步设置空闲连接链表做好准备 */ do { i--; c[i].data = next; c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; } while (i); /* 将ngx_cycle_t结构体中的空闲连接链表free_connections指向connections数组的最后1个元素,也就是第10步所有ngx_connection_t连 接通过data成员组成的单链表的首部。 */ cycle->free_connections = next; cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ /* 在刚刚建立好的连接池中,为所有ngx_listening_t监听对象中的connection成员分配连接,同时对监听端口的读事件设置处理方法 为ngx_event_accept,也就是说,有新连接事件时将调用ngx_event_accept方法建立新连接(详见9.8节中关于如何建立新连接的内容)。 */ ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { #if (NGX_HAVE_REUSEPORT) if (ls[i].reuseport && ls[i].worker != ngx_worker) { continue; } #endif c = ngx_get_connection(ls[i].fd, cycle->log); //从连接池中获取一个ngx_connection_t if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; //把解析到listen配置项信息赋值给ngx_connection_s中的listening中 ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else /* 对监听端口的读事件设置处理方法 为ngx_event_accept,也就是说,有新连接事件时将调用ngx_event_accept方法建立新连接(详见9.8节中关于如何建立新连接的内容)。 */ rev->handler = ngx_event_accept; /* 使用了accept_mutex,暂时不将监听套接字放入epoll中, 而是等到worker抢到accept互斥体后,再放入epoll,避免惊群的发生。 */ //在建连接的时候,为了避免惊群,在accept的时候,只有获取到该原子锁,才把accept添加到epoll事件中,见ngx_process_events_and_timers->ngx_trylock_accept_mutex if (ngx_use_accept_mutex #if (NGX_HAVE_REUSEPORT) && !ls[i].reuseport #endif ) //如果是单进程方式 { continue; } /* 将监听对象连接的读事件添加到事件驱动模块中,这样,epoll等事件模块就开始检测监听服务,并开始向用户提供服务了。 */ //如果ngx_use_accept_mutex为0也就是未开启accept_mutex锁,则在ngx_worker_process_init->ngx_event_process_init 中把accept连接读事件统计到epoll中 //否则在ngx_process_events_and_timers->ngx_process_events_and_timers->ngx_trylock_accept_mutex中把accept连接读事件统计到epoll中 char tmpbuf[256]; snprintf(tmpbuf, sizeof(tmpbuf), "<%25s, %5d> epoll NGX_READ_EVENT(et) read add", NGX_FUNC_LINE); ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, tmpbuf); if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { //如果是epoll则为ngx_epoll_add_event return NGX_ERROR; } #endif } return NGX_OK; }
static ngx_int_t ngx_mbedtls_set_cipher_list(ngx_ssl_t *ssl, const char *ciphers) { static const char ngx_default_ciphers[] = "HIGH:!aNULL:!MD5"; const int *supported_ciphersuites; char cipher_name[MBEDTLS_SSL_CIPHER_MAX_LENGTH]; const char *c, *end, *sep; int i, idx, cipher_id; /* * OpenSSL format cipher lists are somewhat nonsensical as the options * available under PolarSSL are somewhat more limited (most of the things a * user would chose to disable are flat out unsupported). * * Till someone can provide a really good reason otherwise, supporting the * nginx default (HIGH:!aNULL:!MD5) and allowing the user to pass in a * specific list should be sufficient. * * Note: We mimick the OpenSSL behavior of ignoring unknown entries, * mostly because the modules that call this don't bail out even if 0 * is returned (total failure to configure ciphersuites should be * a fatal error at config time). */ supported_ciphersuites = ssl_list_ciphersuites(); for (i = 0; supported_ciphersuites[i] != 0; i++); ssl->ciphersuites = ngx_alloc((i + 1) * sizeof(int), ssl->log); if (ssl->ciphersuites == NULL) { return NGX_ERROR; } if (ngx_strcmp(ciphers, ngx_default_ciphers) == 0) { /* * Special case for the default: "HIGH:!aNULL:!MD5": * * Just using the list from PolarSSL while probably reasonable does * not exclude options that are not included in "HIGH" and also will * (as a last resort) use TLS_RSA_RC4_128_MD5. */ for (i = 0, idx = 0; supported_ciphersuites[idx] != 0; idx++) { switch (supported_ciphersuites[idx]) { /* aNULL ciphers - Never enabled by default, listed for clarity */ case TLS_RSA_WITH_NULL_MD5: case TLS_RSA_WITH_NULL_SHA: case TLS_RSA_WITH_NULL_SHA256: /* MD5 ciphers */ case TLS_RSA_WITH_RC4_128_MD5: /* Weak ciphers */ case TLS_RSA_WITH_DES_CBC_SHA: case TLS_DHE_RSA_WITH_DES_CBC_SHA: case TLS_RSA_WITH_3DES_EDE_CBC_SHA: /* Key size < 128 */ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: /* Key size < 128 */ continue; break; } ssl->ciphersuites[i] = supported_ciphersuites[idx]; i++; } ssl->ciphersuites[i] = 0; return (i != 0) ? NGX_OK : NGX_ERROR; } /* Tokenize the list of ciphers */ c = ciphers; i = 0; end = ciphers + ngx_strlen(ciphers); for (;;) { ssl->ciphersuites[i] = 0; sep = ngx_strchr(c, ':'); if (sep == NULL) { sep = end; } /* FIXME: This is probably somewhat cryptic */ if (sep - c > MBEDTLS_SSL_CIPHER_MAX_LENGTH) { ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, "Out of buffer space when parsing cipher list: %s", ciphers); goto skip; } ngx_memcpy(cipher_name, c, sep - c); cipher_name[sep - c] = '\0'; cipher_id = ssl_get_ciphersuite_id(cipher_name); if (cipher_id == 0) { ngx_log_error(NGX_LOG_EMERG, ssl->log, 0, "Unknown cipher requsted: %s", cipher_name); goto skip; } /* * There are certain ciphers that can be enabled but will never * be returned in the list obtained by ssl_list_ciphersuites(). * * While technically a PolarSSL bug, said ciphers are those that * no one in their right mind will ever enable, so just silently * ignore them (Not supporting the WEAK/NULL ciphers is a feature). * * Additionally, ensure that each cipher is only included once. */ if (ngx_mbedtls_cipher_in_list(cipher_id, supported_ciphersuites) && !ngx_mbedtls_cipher_in_list(cipher_id, ssl->ciphersuites)) { ssl->ciphersuites[i] = cipher_id; i++; } skip: c = sep + 1; if (sep == end) { break; } } return (i != 0) ? NGX_OK : NGX_ERROR; }
//每一个worker进程开始初始化的函数 static ngx_int_t ngx_event_process_init(ngx_cycle_t *cycle) { ngx_uint_t m, i; ngx_event_t *rev, *wev; ngx_listening_t *ls; ngx_connection_t *c, *next, *old; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; ngx_event_module_t *module; //获得相应模块的配置结构 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); //accept_mutex为1时才会使用互斥体 if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) { //当工作进程数目大于1时,用于开启负载均衡情况下,才设置该变量 ngx_use_accept_mutex = 1; //1表示使用互斥体 ngx_accept_mutex_held = 0; //表示是否获得互斥体 ngx_accept_mutex_delay = ecf->accept_mutex_delay; //抢占失败以后,下次再抢的时间,延迟的时间 } else { ngx_use_accept_mutex = 0; //表示不使用互斥体 } #if (NGX_THREADS) ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); if (ngx_posted_events_mutex == NULL) { return NGX_ERROR; } #endif //初始化定时器,这里将会初始化一个红黑树来管理 if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { return NGX_ERROR; } for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } if (ngx_modules[m]->ctx_index != ecf->use) { //不是use配置项指定的事件跳过 continue; } module = ngx_modules[m]->ctx; //调用具体事件模块的函数,如epoll机制的ngx_epoll_init if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { /* fatal */ exit(2); } break; } #if !(NGX_WIN32) //如果设置了timer_resolution配置项,表明要控制时间精度,调用setitimer if (ngx_timer_resolution && !(ngx_event_flags & NGX_USE_TIMER_EVENT)) { struct sigaction sa; struct itimerval itv; ngx_memzero(&sa, sizeof(struct sigaction)); sa.sa_handler = ngx_timer_signal_handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGALRM, &sa, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "sigaction(SIGALRM) failed"); return NGX_ERROR; } itv.it_interval.tv_sec = ngx_timer_resolution / 1000; //秒 itv.it_interval.tv_usec = (ngx_timer_resolution % 1000) * 1000; //微妙 itv.it_value.tv_sec = ngx_timer_resolution / 1000; //循环周期的数 itv.it_value.tv_usec = (ngx_timer_resolution % 1000 ) * 1000; if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "setitimer() failed"); } } if (ngx_event_flags & NGX_USE_FD_EVENT) { struct rlimit rlmt; if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "getrlimit(RLIMIT_NOFILE) failed"); return NGX_ERROR; } cycle->files_n = (ngx_uint_t) rlmt.rlim_cur; //file成员 cycle->files = ngx_calloc(sizeof(ngx_connection_t *) * cycle->files_n, cycle->log); if (cycle->files == NULL) { return NGX_ERROR; } } #endif //创建一个connections数组,直接通过malloc cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; //创建一个读事件数组 cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; } rev = cycle->read_events; for (i = 0; i < cycle->connection_n; i++) { rev[i].closed = 1; rev[i].instance = 1; #if (NGX_THREADS) rev[i].lock = &c[i].lock; rev[i].own_lock = &c[i].lock; #endif } //创建一个写事件数组 cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; } wev = cycle->write_events; for (i = 0; i < cycle->connection_n; i++) { wev[i].closed = 1; #if (NGX_THREADS) wev[i].lock = &c[i].lock; wev[i].own_lock = &c[i].lock; #endif } i = cycle->connection_n; next = NULL; //初始化整个connections数组 do { i--; c[i].data = next; //串联起来 c[i].read = &cycle->read_events[i]; c[i].write = &cycle->write_events[i]; c[i].fd = (ngx_socket_t) -1; next = &c[i]; #if (NGX_THREADS) c[i].lock = 0; #endif } while (i); cycle->free_connections = next; //指向一个可用的slot cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ //为每一个监听套接字分配一个connection ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { c = ngx_get_connection(ls[i].fd, cycle->log); //获得一个可用的connection //对于每一个监听套接口创建对应的connection连接对象 if (c == NULL) { return NGX_ERROR; } c->log = &ls[i].log; c->listening = &ls[i]; ls[i].connection = c; rev = c->read; rev->log = c->log; rev->accept = 1; //读事件发生 #if (NGX_HAVE_DEFERRED_ACCEPT) rev->deferred_accept = ls[i].deferred_accept; #endif if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) { if (ls[i].previous) { /* * delete the old accept events that were bound to * the old cycle read events array */ old = ls[i].previous->connection; if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) { return NGX_ERROR; } old->fd = (ngx_socket_t) -1; } } #if (NGX_WIN32) if (ngx_event_flags & NGX_USE_IOCP_EVENT) { ngx_iocp_conf_t *iocpcf; rev->handler = ngx_event_acceptex; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } ls[i].log.handler = ngx_acceptex_log_error; iocpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_iocp_module); if (ngx_event_post_acceptex(&ls[i], iocpcf->post_acceptex) == NGX_ERROR) { return NGX_ERROR; } } else { rev->handler = ngx_event_accept; if (ngx_use_accept_mutex) { continue; } if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #else //ngx_process_events_and_timers rev->handler = ngx_event_accept; //监听套接字的读事件回调 if (ngx_use_accept_mutex) { //设置了该参数,也就跳过了后面的将监听套接口添加到事件监控事件里,避免惊群 continue; } if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { if (ngx_add_conn(c) == NGX_ERROR) { return NGX_ERROR; } } else { //没有使用accept_mutex时,就将监听套接字放入到epoll中 if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } } #endif } return NGX_OK; }
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { //确保一个bucket至少可以一个实际的元素以及结束哨兵。 if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } //计算一个bucket除去结束哨兵所占空间后的实际可用空间大小 bucket_size = hinit->bucket_size - sizeof(void *); //2*sizeof(void *) 一个实际元素所需的内存空间的最小值 //bucket_size * ( 2*sizeof(void *)):一个bucket可以存储的最大实际元素个数 //总实际元素个数netls除以这个值也就是最少所需要的bucket个数 start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size <= hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %ui %ui \"%V\"", size, key, test[key], &names[n].key); #endif if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } size--; ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0, "could not build optimal %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i; " "ignoring %s_bucket_size", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size, hinit->name); found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_short) names[n].key.len; ngx_strlow(elt->name, names[n].key.data, names[n].key.len); test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; #if 0 for (i = 0; i < size; i++) { ngx_str_t val; ngx_uint_t key; elt = buckets[i]; if (elt == NULL) { ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: NULL", i); continue; } while (elt->value) { val.len = elt->len; val.data = &elt->name[0]; key = hinit->key(val.data, val.len); ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %p \"%V\" %ui", i, elt, &val, key); elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } #endif return NGX_OK; }
ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) { char *buf; off_t size; size_t len; ssize_t n; ngx_fd_t fd, nfd; ngx_int_t rc; ngx_file_info_t fi; rc = NGX_ERROR; buf = NULL; nfd = NGX_INVALID_FILE; fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, ngx_open_file_n " \"%s\" failed", from); goto failed; } if (cf->size != -1) { size = cf->size; } else { if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", from); goto failed; } size = ngx_file_size(&fi); } len = cf->buf_size ? cf->buf_size : 65536; if ((off_t) len > size) { len = (size_t) size; } buf = ngx_alloc(len, cf->log); if (buf == NULL) { goto failed; } nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, cf->access); if (nfd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, ngx_open_file_n " \"%s\" failed", to); goto failed; } while (size > 0) { if ((off_t) len > size) { len = (size_t) size; } n = ngx_read_fd(fd, buf, len); if (n == -1) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_read_fd_n " \"%s\" failed", from); goto failed; } if ((size_t) n != len) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, ngx_read_fd_n " has read only %z of %O from %s", n, size, from); goto failed; } n = ngx_write_fd(nfd, buf, len); if (n == -1) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_write_fd_n " \"%s\" failed", to); goto failed; } if ((size_t) n != len) { ngx_log_error(NGX_LOG_ALERT, cf->log, 0, ngx_write_fd_n " has written only %z of %O to %s", n, size, to); goto failed; } size -= n; } if (cf->time != -1) { if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_set_file_time_n " \"%s\" failed", to); goto failed; } } rc = NGX_OK; failed: if (nfd != NGX_INVALID_FILE) { if (ngx_close_file(nfd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " \"%s\" failed", to); } } if (fd != NGX_INVALID_FILE) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " \"%s\" failed", from); } } if (buf) { ngx_free(buf); } return rc; }
ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) { u_char *name; ngx_err_t err; ngx_copy_file_t cf; #if !(NGX_WIN32) if (ext->access) { if (ngx_change_file_access(src->data, ext->access) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_change_file_access_n " \"%s\" failed", src->data); err = 0; goto failed; } } #endif if (ext->time != -1) { if (ngx_set_file_time(src->data, ext->fd, ext->time) != NGX_OK) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_set_file_time_n " \"%s\" failed", src->data); err = 0; goto failed; } } if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { return NGX_OK; } err = ngx_errno; if (err == NGX_ENOPATH) { if (!ext->create_path) { goto failed; } err = ngx_create_full_path(to->data, ngx_dir_access(ext->path_access)); if (err) { ngx_log_error(NGX_LOG_CRIT, ext->log, err, ngx_create_dir_n " \"%s\" failed", to->data); err = 0; goto failed; } if (ngx_rename_file(src->data, to->data) != NGX_FILE_ERROR) { return NGX_OK; } err = ngx_errno; } #if (NGX_WIN32) if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) { err = ngx_win32_rename_file(src, to, ext->log); if (err == 0) { return NGX_OK; } } #endif if (err == NGX_EXDEV) { cf.size = -1; cf.buf_size = 0; cf.access = ext->access; cf.time = ext->time; cf.log = ext->log; name = ngx_alloc(to->len + 1 + 10 + 1, ext->log); if (name == NULL) { return NGX_ERROR; } (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data, (uint32_t) ngx_next_temp_number(0)); if (ngx_copy_file(src->data, name, &cf) == NGX_OK) { if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) { ngx_free(name); if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", src->data); return NGX_ERROR; } return NGX_OK; } ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_rename_file_n " \"%s\" to \"%s\" failed", name, to->data); if (ngx_delete_file(name) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", name); } } ngx_free(name); err = 0; } failed: if (ext->delete_file) { if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", src->data); } } if (err) { ngx_log_error(NGX_LOG_CRIT, ext->log, err, ngx_rename_file_n " \"%s\" to \"%s\" failed", src->data, to->data); } return NGX_ERROR; }
static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) { u_char *name, *p; size_t len; time_t now, wait; ngx_path_t *path; ngx_queue_t *q; ngx_http_file_cache_node_t *fcn; u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache expire"); path = cache->path; len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; name = ngx_alloc(len + 1, ngx_cycle->log); if (name == NULL) { return 10; } ngx_memcpy(name, path->name.data, path->name.len); now = ngx_time(); ngx_shmtx_lock(&cache->shpool->mutex); for ( ;; ) { if (ngx_quit || ngx_terminate) { wait = 1; break; } if (ngx_queue_empty(&cache->sh->queue)) { wait = 10; break; } q = ngx_queue_last(&cache->sh->queue); fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); wait = fcn->expire - now; if (wait > 0) { wait = wait > 10 ? 10 : wait; break; } ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache expire: #%d %d %02xd%02xd%02xd%02xd", fcn->count, fcn->exists, fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); if (fcn->count == 0) { ngx_http_file_cache_delete(cache, q, name); continue; } if (fcn->deleting) { wait = 1; break; } p = ngx_hex_dump(key, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); (void) ngx_hex_dump(p, fcn->key, len); /* * abnormally exited workers may leave locked cache entries, * and although it may be safe to remove them completely, * we prefer to just move them to the top of the inactive queue */ ngx_queue_remove(q); fcn->expire = ngx_time() + cache->inactive; ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "ignore long locked inactive cache entry %*s, count:%d", 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); } ngx_shmtx_unlock(&cache->shpool->mutex); ngx_free(name); return wait; }
ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) { u_char *elts; size_t len; u_short *test; ngx_uint_t i, n, key, size, start, bucket_size; ngx_hash_elt_t *elt, **buckets; for (n = 0; n < nelts; n++) { if (names[n].key.len >= 255) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "the \"%V\" value to hash is to long: %uz bytes, " "the maximum length can be 255 bytes only", &names[n].key, names[n].key.len); return NGX_ERROR; } if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should " "increase %s_bucket_size: %i", hinit->name, hinit->name, hinit->bucket_size); return NGX_ERROR; } } test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log); if (test == NULL) { return NGX_ERROR; } bucket_size = hinit->bucket_size - sizeof(void *); start = nelts / (bucket_size / (2 * sizeof(void *))); start = start ? start : 1; if (hinit->max_size > 10000 && hinit->max_size / nelts < 100) { start = hinit->max_size - 1000; } for (size = start; size < hinit->max_size; size++) { ngx_memzero(test, size * sizeof(u_short)); for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %ui %ui \"%V\"", size, key, test[key], &names[n].key); #endif if (test[key] > (u_short) bucket_size) { goto next; } } goto found; next: continue; } ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, "could not build the %s, you should increase " "either %s_max_size: %i or %s_bucket_size: %i", hinit->name, hinit->name, hinit->max_size, hinit->name, hinit->bucket_size); ngx_free(test); return NGX_ERROR; found: for (i = 0; i < size; i++) { test[i] = sizeof(void *); } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } len = 0; for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size)); len += test[i]; } if (hinit->hash == NULL) { hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t) + size * sizeof(ngx_hash_elt_t *)); if (hinit->hash == NULL) { ngx_free(test); return NGX_ERROR; } buckets = (ngx_hash_elt_t **) ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t)); } else { buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *)); if (buckets == NULL) { ngx_free(test); return NGX_ERROR; } } elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size); if (elts == NULL) { ngx_free(test); return NGX_ERROR; } elts = ngx_align_ptr(elts, ngx_cacheline_size); for (i = 0; i < size; i++) { if (test[i] == sizeof(void *)) { continue; } buckets[i] = (ngx_hash_elt_t *) elts; elts += test[i]; } for (i = 0; i < size; i++) { test[i] = 0; } for (n = 0; n < nelts; n++) { if (names[n].key.data == NULL) { continue; } key = names[n].key_hash % size; elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]); elt->value = names[n].value; elt->len = (u_char) names[n].key.len; for (i = 0; i < names[n].key.len; i++) { elt->name[i] = ngx_tolower(names[n].key.data[i]); } test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); } for (i = 0; i < size; i++) { if (buckets[i] == NULL) { continue; } elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]); elt->value = NULL; } ngx_free(test); hinit->hash->buckets = buckets; hinit->hash->size = size; #if 0 for (i = 0; i < size; i++) { ngx_str_t val; ngx_uint_t key; elt = buckets[i]; if (elt == NULL) { ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: NULL", i); continue; } while (elt->value) { val.len = elt->len; val.data = &elt->name[0]; key = hinit->key(val.data, val.len); ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, "%ui: %p \"%V\" %ui", i, elt, &val, key); elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len, sizeof(void *)); } } #endif return NGX_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; u_char *p; off_t size; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf, *tbuf; ngx_conf_file_t *prev, conf_file; ngx_conf_dump_t *cd; enum { parse_file = 0, parse_block, parse_param } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; cf->conf_file = &conf_file; if (ngx_fd_info(fd, &cf->conf_file->file.info) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = &buf; buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log); if (buf.start == NULL) { goto failed; } buf.pos = buf.start; buf.last = buf.start; buf.end = buf.last + NGX_CONF_BUFFER; buf.temporary = 1; cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; type = parse_file; if (ngx_dump_config #if (NGX_DEBUG) || 1 #endif ) { p = ngx_pstrdup(cf->cycle->pool, filename); if (p == NULL) { goto failed; } size = ngx_file_size(&cf->conf_file->file.info); tbuf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size); if (tbuf == NULL) { goto failed; } cd = ngx_array_push(&cf->cycle->config_dump); if (cd == NULL) { goto failed; } cd->name.len = filename->len; cd->name.data = p; cd->buffer = tbuf; cf->conf_file->dump = tbuf; } else { cf->conf_file->dump = NULL; } } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; } else { type = parse_param; } /*这里解析指令的方式是"读取一条、检查一条、解析一条"的方式解析配置文件,这里的一条是以分号或者花括号"{"、"}"为单位,如果遇到嵌套的花括号,则先处理嵌套的指令*/ for ( ;; ) { /*将配置文件中当前的一条配置指令读取到内存中,判断配置语法是否使用正确,并将该指令保存到cycle->args数组中*/ rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } if (rc == NGX_CONF_BLOCK_DONE) { if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_FILE_DONE) { if (type == parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_BLOCK_START) { if (type == parse_param) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ /*如果该指令定义了自定义处理函数,则调用自定义处理函数进行解析*/ if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ if (rc == NGX_CONF_BLOCK_START) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"{\""); goto failed; } rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } if (rv == NGX_CONF_ERROR) { goto failed; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); goto failed; } /*调用指令的处理函数*/ rc = ngx_conf_handler(cf, rc); if (rc == NGX_ERROR) { goto failed; } } failed: rc = NGX_ERROR; done: if (filename) { if (cf->conf_file->buffer->start) { ngx_free(cf->conf_file->buffer->start); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", filename->data); rc = NGX_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t buf; ngx_conf_file_t *prev, conf_file; enum { parse_file = 0, parse_block, parse_param } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; prev = NULL; #endif if (filename) { /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", filename->data); return NGX_CONF_ERROR; } prev = cf->conf_file; cf->conf_file = &conf_file; if (ngx_fd_info(fd, &cf->conf_file->file.info) == -1) { ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno, ngx_fd_info_n " \"%s\" failed", filename->data); } cf->conf_file->buffer = &buf; buf.start = ngx_alloc(NGX_CONF_BUFFER, cf->log); if (buf.start == NULL) { goto failed; } buf.pos = buf.start; buf.last = buf.start; buf.end = buf.last + NGX_CONF_BUFFER; buf.temporary = 1; cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; cf->conf_file->file.offset = 0; cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; type = parse_file; } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { type = parse_block; } else { type = parse_param; } for ( ;; ) { rc = ngx_conf_read_token(cf); /* * ngx_conf_read_token() may return * * NGX_ERROR there is error * NGX_OK the token terminated by ";" was found * NGX_CONF_BLOCK_START the token terminated by "{" was found * NGX_CONF_BLOCK_DONE the "}" was found * NGX_CONF_FILE_DONE the configuration file is done */ if (rc == NGX_ERROR) { goto done; } if (rc == NGX_CONF_BLOCK_DONE) { if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_FILE_DONE) { if (type == parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, expecting \"}\""); goto failed; } goto done; } if (rc == NGX_CONF_BLOCK_START) { if (type == parse_param) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "block directives are not supported " "in -g option"); goto failed; } } /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ if (cf->handler) { /* * the custom handler, i.e., that is used in the http's * "types { ... }" directive */ rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; } if (rv == NGX_CONF_ERROR) { goto failed; } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv); goto failed; } rc = ngx_conf_handler(cf, rc); if (rc == NGX_ERROR) { goto failed; } } failed: rc = NGX_ERROR; done: if (filename) { if (cf->conf_file->buffer->start) { ngx_free(cf->conf_file->buffer->start); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_close_file_n " %s failed", filename->data); return NGX_CONF_ERROR; } cf->conf_file = prev; } if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } return NGX_CONF_OK; }
static ngx_int_t ngx_http_dav_copy_dir_time(ngx_tree_ctx_t *ctx, ngx_str_t *path) { u_char *p, *dir; size_t len; ngx_http_dav_copy_ctx_t *copy; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy dir time: \"%s\"", path->data); copy = ctx->data; len = copy->path.len + path->len; dir = ngx_alloc(len + 1, ctx->log); if (dir == NULL) { return NGX_ABORT; } p = ngx_cpymem(dir, copy->path.data, copy->path.len); (void) ngx_cpystrn(p, path->data + copy->len, path->len - copy->len + 1); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy dir time to: \"%s\"", dir); #if (NGX_WIN32) { ngx_fd_t fd; fd = ngx_open_file(dir, NGX_FILE_RDWR, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, dir); goto failed; } if (ngx_set_file_time(NULL, fd, ctx->mtime) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, ngx_set_file_time_n " \"%s\" failed", dir); } if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, ngx_close_file_n " \"%s\" failed", dir); } } failed: #else if (ngx_set_file_time(dir, 0, ctx->mtime) != NGX_OK) { ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, ngx_set_file_time_n " \"%s\" failed", dir); } #endif ngx_free(dir); return NGX_OK; }
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const #endif u_char *p; int n; size_t len; ngx_str_t response; X509_STORE *store; STACK_OF(X509) *chain; OCSP_CERTID *id; OCSP_RESPONSE *ocsp; OCSP_BASICRESP *basic; ngx_ssl_stapling_t *staple; ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; staple = ctx->data; ocsp = NULL; basic = NULL; id = NULL; if (ctx->code != 200) { goto error; } /* check the response */ len = ctx->response->last - ctx->response->pos; p = ctx->response->pos; ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (ocsp == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "d2i_OCSP_RESPONSE() failed"); goto error; } n = OCSP_response_status(ocsp); if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "OCSP response not successful (%d: %s)", n, OCSP_response_status_str(n)); goto error; } basic = OCSP_response_get1_basic(ocsp); if (basic == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_response_get1_basic() failed"); goto error; } store = SSL_CTX_get_cert_store(staple->ssl_ctx); if (store == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "SSL_CTX_get_cert_store() failed"); goto error; } #if OPENSSL_VERSION_NUMBER >= 0x10001000L SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); #else chain = staple->ssl_ctx->extra_certs; #endif if (OCSP_basic_verify(basic, chain, store, staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_basic_verify() failed"); goto error; } id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (id == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "OCSP_cert_to_id() failed"); goto error; } if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, &thisupdate, &nextupdate) != 1) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status not found in the OCSP response"); goto error; } if (n != V_OCSP_CERTSTATUS_GOOD) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status \"%s\" in the OCSP response", OCSP_cert_status_str(n)); goto error; } if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_check_validity() failed"); goto error; } OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(ocsp); /* copy the response to memory not in ctx->pool */ response.len = len; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { goto done; } ngx_memcpy(response.data, ctx->response->pos, response.len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp response, %s, %uz", OCSP_cert_status_str(n), response.len); if (staple->staple.data) { ngx_free(staple->staple.data); } staple->staple = response; done: staple->loading = 0; staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */ ngx_ssl_ocsp_done(ctx); return; error: staple->loading = 0; staple->valid = ngx_time() + 300; /* ssl_stapling_err_valid */ if (id) { OCSP_CERTID_free(id); } if (basic) { OCSP_BASICRESP_free(basic); } if (ocsp) { OCSP_RESPONSE_free(ocsp); } ngx_ssl_ocsp_done(ctx); }
ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree) { void *data, *prev; u_char *p, *name; size_t len; ngx_int_t rc; ngx_err_t err; ngx_str_t file, buf; ngx_dir_t dir; buf.len = 0; buf.data = NULL; ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "walk tree \"%V\"", tree); if (ngx_open_dir(tree, &dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_open_dir_n " \"%s\" failed", tree->data); return NGX_ERROR; } prev = ctx->data; if (ctx->alloc) { data = ngx_alloc(ctx->alloc, ctx->log); if (data == NULL) { goto failed; } if (ctx->init_handler(data, prev) == NGX_ABORT) { goto failed; } ctx->data = data; } else { data = NULL; } for ( ;; ) { ngx_set_errno(0); if (ngx_read_dir(&dir) == NGX_ERROR) { err = ngx_errno; if (err == NGX_ENOMOREFILES) { rc = NGX_OK; } else { ngx_log_error(NGX_LOG_CRIT, ctx->log, err, ngx_read_dir_n " \"%s\" failed", tree->data); rc = NGX_ERROR; } goto done; } len = ngx_de_namelen(&dir); name = ngx_de_name(&dir); ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree name %uz:\"%s\"", len, name); if (len == 1 && name[0] == '.') { continue; } if (len == 2 && name[0] == '.' && name[1] == '.') { continue; } file.len = tree->len + 1 + len; if (file.len + NGX_DIR_MASK_LEN > buf.len) { if (buf.len) { ngx_free(buf.data); } buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN; buf.data = ngx_alloc(buf.len + 1, ctx->log); if (buf.data == NULL) { goto failed; } } p = ngx_cpymem(buf.data, tree->data, tree->len); *p++ = '/'; ngx_memcpy(p, name, len + 1); file.data = buf.data; ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree path \"%s\"", file.data); if (!dir.valid_info) { if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_de_info_n " \"%s\" failed", file.data); continue; } } if (ngx_de_is_file(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree file \"%s\"", file.data); ctx->size = ngx_de_size(&dir); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->file_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else if (ngx_de_is_dir(&dir)) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree enter dir \"%s\"", file.data); ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) { goto failed; } if (ngx_walk_tree(ctx, &file) == NGX_ABORT) { goto failed; } ctx->access = ngx_de_access(&dir); ctx->mtime = ngx_de_mtime(&dir); if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) { goto failed; } } else { ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, "tree special \"%s\"", file.data); if (ctx->spec_handler(ctx, &file) == NGX_ABORT) { goto failed; } } } failed: rc = NGX_ABORT; done: if (buf.len) { ngx_free(buf.data); } if (data) { ngx_free(data); ctx->data = prev; } if (ngx_close_dir(&dir) == NGX_ERROR) { ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, ngx_close_dir_n " \"%s\" failed", tree->data); } return rc; }
static int ngx_http_lua_ngx_timer_at(lua_State *L) { int nargs, co_ref; u_char *p; lua_State *vm; /* the main thread */ lua_State *co; ngx_msec_t delay; ngx_event_t *ev; ngx_http_request_t *r; ngx_connection_t *saved_c = NULL; ngx_http_lua_ctx_t *ctx; #if 0 ngx_http_connection_t *hc; #endif ngx_http_lua_timer_ctx_t *tctx = NULL; ngx_http_lua_main_conf_t *lmcf; #if 0 ngx_http_core_main_conf_t *cmcf; #endif nargs = lua_gettop(L); if (nargs < 2) { return luaL_error(L, "expecting at least 2 arguments but got %d", nargs); } delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request"); } ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ngx_exiting && delay > 0) { lua_pushnil(L); lua_pushliteral(L, "process exiting"); return 2; } lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); if (lmcf->pending_timers >= lmcf->max_pending_timers) { lua_pushnil(L); lua_pushliteral(L, "too many pending timers"); return 2; } if (lmcf->watcher == NULL) { /* create the watcher fake connection */ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "lua creating fake watcher connection"); if (ngx_cycle->files) { saved_c = ngx_cycle->files[0]; } lmcf->watcher = ngx_get_connection(0, ngx_cycle->log); if (ngx_cycle->files) { ngx_cycle->files[0] = saved_c; } if (lmcf->watcher == NULL) { return luaL_error(L, "no memory"); } /* to work around the -1 check in ngx_worker_process_cycle: */ lmcf->watcher->fd = (ngx_socket_t) -2; lmcf->watcher->idle = 1; lmcf->watcher->read->handler = ngx_http_lua_abort_pending_timers; lmcf->watcher->data = lmcf; } vm = ngx_http_lua_get_lua_vm(r, ctx); co = lua_newthread(vm); /* L stack: time func [args] thread */ ngx_http_lua_probe_user_coroutine_create(r, L, co); lua_createtable(co, 0, 0); /* the new globals table */ /* co stack: global_tb */ lua_createtable(co, 0, 1); /* the metatable */ ngx_http_lua_get_globals_table(co); lua_setfield(co, -2, "__index"); lua_setmetatable(co, -2); /* co stack: global_tb */ ngx_http_lua_set_globals_table(co); /* co stack: <empty> */ dd("stack top: %d", lua_gettop(L)); lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ /* L stack: time func [args] thread */ /* vm stack: empty */ lua_pushvalue(L, 2); /* copy entry function to top of L*/ /* L stack: time func [args] thread func */ lua_xmove(L, co, 1); /* move entry function from L to co */ /* L stack: time func [args] thread */ /* co stack: func */ ngx_http_lua_get_globals_table(co); lua_setfenv(co, -2); /* co stack: func */ lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); /* L stack: time func [args] thread corountines */ lua_pushvalue(L, -2); /* L stack: time func [args] thread coroutines thread */ co_ref = luaL_ref(L, -2); lua_pop(L, 1); /* L stack: time func [args] thread */ if (nargs > 2) { lua_pop(L, 1); /* L stack: time func [args] */ lua_xmove(L, co, nargs - 2); /* L stack: time func */ /* co stack: func [args] */ } p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), r->connection->log); if (p == NULL) { goto nomem; } ev = (ngx_event_t *) p; ngx_memzero(ev, sizeof(ngx_event_t)); p += sizeof(ngx_event_t); tctx = (ngx_http_lua_timer_ctx_t *) p; tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; tctx->main_conf = r->main_conf; tctx->srv_conf = r->srv_conf; tctx->loc_conf = r->loc_conf; tctx->lmcf = lmcf; tctx->pool = ngx_create_pool(128, ngx_cycle->log); if (tctx->pool == NULL) { goto nomem; } if (r->connection) { tctx->listening = r->connection->listening; } else { tctx->listening = NULL; } if (r->connection->addr_text.len) { tctx->client_addr_text.data = ngx_palloc(tctx->pool, r->connection->addr_text.len); if (tctx->client_addr_text.data == NULL) { goto nomem; } ngx_memcpy(tctx->client_addr_text.data, r->connection->addr_text.data, r->connection->addr_text.len); tctx->client_addr_text.len = r->connection->addr_text.len; } else { tctx->client_addr_text.len = 0; tctx->client_addr_text.data = NULL; } if (ctx && ctx->vm_state) { tctx->vm_state = ctx->vm_state; tctx->vm_state->count++; } else { tctx->vm_state = NULL; } ev->handler = ngx_http_lua_timer_handler; ev->data = tctx; ev->log = ngx_cycle->log; lmcf->pending_timers++; ngx_add_timer(ev, delay); lua_pushinteger(L, 1); return 1; nomem: if (tctx && tctx->pool) { ngx_destroy_pool(tctx->pool); } lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); luaL_unref(L, -1, co_ref); return luaL_error(L, "no memory"); }
ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name, ngx_open_file_info_t *of, ngx_pool_t *pool) { time_t now; uint32_t hash; ngx_int_t rc; ngx_file_info_t fi; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; ngx_pool_cleanup_file_t *clnf; ngx_open_file_cache_cleanup_t *ofcln; of->fd = NGX_INVALID_FILE; of->err = 0; if (cache == NULL) { if (of->test_only) { if (ngx_file_info_wrapper(name, of, &fi, pool->log) == NGX_FILE_ERROR) { return NGX_ERROR; } of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); of->fs_size = ngx_file_fs_size(&fi); of->is_dir = ngx_is_dir(&fi); of->is_file = ngx_is_file(&fi); of->is_link = ngx_is_link(&fi); of->is_exec = ngx_is_exec(&fi); return NGX_OK; } cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); if (cln == NULL) { return NGX_ERROR; } rc = ngx_open_and_stat_file(name, of, pool->log); if (rc == NGX_OK && !of->is_dir) { cln->handler = ngx_pool_cleanup_file; clnf = cln->data; clnf->fd = of->fd; clnf->name = name->data; clnf->log = pool->log; } return rc; } cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); if (cln == NULL) { return NGX_ERROR; } now = ngx_time(); hash = ngx_crc32_long(name->data, name->len); file = ngx_open_file_lookup(cache, name, hash); if (file) { file->uses++; ngx_queue_remove(&file->queue); if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { /* file was not used often enough to keep open */ rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } goto add_event; } if (file->use_event || (file->event == NULL && (of->uniq == 0 || of->uniq == file->uniq) && now - file->created < of->valid #if (NGX_HAVE_OPENAT) && of->disable_symlinks == file->disable_symlinks && of->disable_symlinks_from == file->disable_symlinks_from #endif )) { if (file->err == 0) { of->fd = file->fd; of->uniq = file->uniq; of->mtime = file->mtime; of->size = file->size; of->is_dir = file->is_dir; of->is_file = file->is_file; of->is_link = file->is_link; of->is_exec = file->is_exec; of->is_directio = file->is_directio; if (!file->is_dir) { file->count++; ngx_open_file_add_event(cache, file, of, pool->log); } } else { of->err = file->err; #if (NGX_HAVE_OPENAT) of->failed = file->disable_symlinks ? ngx_openat_file_n : ngx_open_file_n; #else of->failed = ngx_open_file_n; #endif } goto found; } ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, "retest open file: %s, fd:%d, c:%d, e:%d", file->name, file->fd, file->count, file->err); if (file->is_dir) { /* * chances that directory became file are very small * so test_dir flag allows to use a single syscall * in ngx_file_info() instead of three syscalls */ of->test_dir = 1; } of->fd = file->fd; of->uniq = file->uniq; rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } if (of->is_dir) { if (file->is_dir || file->err) { goto update; } /* file became directory */ } else if (of->err == 0) { /* file */ if (file->is_dir || file->err) { goto add_event; } if (of->uniq == file->uniq) { if (file->event) { file->use_event = 1; } of->is_directio = file->is_directio; goto update; } /* file was changed */ } else { /* error to cache */ if (file->err || file->is_dir) { goto update; } /* file was removed, etc. */ } if (file->count == 0) { ngx_open_file_del_event(file); if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } goto add_event; } ngx_rbtree_delete(&cache->rbtree, &file->node); cache->current--; file->close = 1; goto create; } /* not found */ rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; } create: if (cache->current >= cache->max) { ngx_expire_old_cached_files(cache, 0, pool->log); } file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log); if (file == NULL) { goto failed; } file->name = ngx_alloc(name->len + 1, pool->log); if (file->name == NULL) { ngx_free(file); file = NULL; goto failed; } ngx_cpystrn(file->name, name->data, name->len + 1); file->node.key = hash; ngx_rbtree_insert(&cache->rbtree, &file->node); cache->current++; file->uses = 1; file->count = 0; file->use_event = 0; file->event = NULL; add_event: ngx_open_file_add_event(cache, file, of, pool->log); update: file->fd = of->fd; file->err = of->err; #if (NGX_HAVE_OPENAT) file->disable_symlinks = of->disable_symlinks; file->disable_symlinks_from = of->disable_symlinks_from; #endif if (of->err == 0) { file->uniq = of->uniq; file->mtime = of->mtime; file->size = of->size; file->close = 0; file->is_dir = of->is_dir; file->is_file = of->is_file; file->is_link = of->is_link; file->is_exec = of->is_exec; file->is_directio = of->is_directio; if (!of->is_dir) { file->count++; } } file->created = now; found: file->accessed = now; ngx_queue_insert_head(&cache->expire_queue, &file->queue); ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", file->name, file->fd, file->count, file->err, file->uses); if (of->err == 0) { if (!of->is_dir) { cln->handler = ngx_open_file_cleanup; ofcln = cln->data; ofcln->cache = cache; ofcln->file = file; ofcln->min_uses = of->min_uses; ofcln->log = pool->log; } return NGX_OK; } return NGX_ERROR; failed: if (file) { ngx_rbtree_delete(&cache->rbtree, &file->node); cache->current--; if (file->count == 0) { if (file->fd != NGX_INVALID_FILE) { if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file->name); } } ngx_free(file->name); ngx_free(file); } else { file->close = 1; } } if (of->fd != NGX_INVALID_FILE) { if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, ngx_close_file_n " \"%V\" failed", name); } } return NGX_ERROR; }
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv) { char **env, *var; u_char *p; ngx_uint_t i, n; ngx_pid_t pid; ngx_exec_ctx_t ctx; ngx_core_conf_t *ccf; ngx_listening_t *ls; ngx_memzero(&ctx, sizeof(ngx_exec_ctx_t)); ctx.path = argv[0]; ctx.name = "new binary process"; ctx.argv = argv; n = 2; env = ngx_set_environment(cycle, &n); if (env == NULL) { return NGX_INVALID_PID; } var = ngx_alloc(sizeof(NGINX_VAR) + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, cycle->log); if (var == NULL) { ngx_free(env); return NGX_INVALID_PID; } p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { p = ngx_sprintf(p, "%ud;", ls[i].fd); } *p = '\0'; env[n++] = var; #if (NGX_SETPROCTITLE_USES_ENV) /* allocate the spare 300 bytes for the new binary process title */ env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; #endif env[n] = NULL; #if (NGX_DEBUG) { char **e; for (e = env; *e; e++) { ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e); } } #endif ctx.envp = (char *const *) env; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s to %s failed " "before executing new binary process \"%s\"", ccf->pid.data, ccf->oldpid.data, argv[0]); ngx_free(env); ngx_free(var); return NGX_INVALID_PID; } pid = ngx_execute(cycle, &ctx); if (pid == NGX_INVALID_PID) { if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_rename_file_n " %s back to %s failed after " "an attempt to execute new binary process \"%s\"", ccf->oldpid.data, ccf->pid.data, argv[0]); } } ngx_free(env); ngx_free(var); return pid; }
static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) { ngx_open_file_cache_event_t *fev; if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) || !of->events || file->event || of->fd == NGX_INVALID_FILE || file->uses < of->min_uses) { return; } file->use_event = 0; file->event = ngx_calloc(sizeof(ngx_event_t), log); if (file->event== NULL) { return; } fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); if (fev == NULL) { ngx_free(file->event); file->event = NULL; return; } fev->fd = of->fd; fev->file = file; fev->cache = cache; file->event->handler = ngx_open_file_cache_remove; file->event->data = fev; /* * although vnode event may be called while ngx_cycle->poll * destruction, however, cleanup procedures are run before any * memory freeing and events will be canceled. */ file->event->log = ngx_cycle->log; if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) != NGX_OK) { ngx_free(file->event->data); ngx_free(file->event); file->event = NULL; return; } /* * we do not set file->use_event here because there may be a race * condition: a file may be deleted between opening the file and * adding event, so we rely upon event notification only after * one file revalidation on next file access */ return; }
static ngx_int_t ngx_devpoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) { size_t n; ngx_devpoll_conf_t *dpcf; dpcf = ngx_event_get_conf(cycle->conf_ctx, ngx_devpoll_module); if (dp == -1) { dp = open("/dev/poll", O_RDWR); if (dp == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "open(/dev/poll) failed"); return NGX_ERROR; } } if (max_changes < dpcf->changes) { if (nchanges) { n = nchanges * sizeof(struct pollfd); if (write(dp, change_list, n) != (ssize_t) n) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "write(/dev/poll) failed"); return NGX_ERROR; } nchanges = 0; } if (change_list) { ngx_free(change_list); } change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes, cycle->log); if (change_list == NULL) { return NGX_ERROR; } if (change_index) { ngx_free(change_index); } change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes, cycle->log); if (change_index == NULL) { return NGX_ERROR; } } max_changes = dpcf->changes; if (nevents < dpcf->events) { if (event_list) { ngx_free(event_list); } event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events, cycle->log); if (event_list == NULL) { return NGX_ERROR; } } nevents = dpcf->events; ngx_io = ngx_os_io; ngx_event_actions = ngx_devpoll_module_ctx.actions; ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT; return NGX_OK; }
static ngx_int_t ngx_rtmp_exec_run(ngx_rtmp_exec_t *e) { #if !(NGX_WIN32) ngx_pid_t pid; int fd, maxfd; int pipefd[2]; int ret; ngx_rtmp_exec_conf_t *ec; ngx_str_t *arg_in, a; char **args, **arg_out; ngx_uint_t n; ec = e->conf; ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: starting child '%V'", &ec->cmd); if (e->active) { ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: already active '%V'", &ec->cmd); return NGX_OK; } if (pipe(pipefd) == -1) { ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: pipe failed"); return NGX_ERROR; } /* make pipe write end survive through exec */ ret = fcntl(pipefd[1], F_GETFD); if (ret != -1) { ret &= ~FD_CLOEXEC; ret = fcntl(pipefd[1], F_SETFD, ret); } if (ret == -1) { close(pipefd[0]); close(pipefd[1]); ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: fcntl failed"); return NGX_ERROR; } pid = fork(); switch (pid) { case -1: close(pipefd[0]); close(pipefd[1]); ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: fork failed"); return NGX_ERROR; case 0: /* child */ #if (NGX_LINUX) prctl(PR_SET_PDEATHSIG, e->kill_signal, 0, 0, 0); #endif /* close all descriptors but pipe write end */ maxfd = sysconf(_SC_OPEN_MAX); for (fd = 0; fd < maxfd; ++fd) { if (fd == pipefd[1]) { continue; } close(fd); } fd = open("/dev/null", O_RDWR); dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); args = ngx_alloc((ec->args.nelts + 2) * sizeof(char *), e->log); if (args == NULL) { exit(1); } arg_in = ec->args.elts; arg_out = args; *arg_out++ = (char *) ec->cmd.data; for (n = 0; n < ec->args.nelts; n++, ++arg_in) { if (e->session == NULL) { a = *arg_in; } else { ngx_rtmp_eval(e->session, arg_in, ngx_rtmp_exec_eval_p, &a); } if (ngx_rtmp_eval_streams(&a) != NGX_DONE) { continue; } *arg_out++ = (char *) a.data; } *arg_out = NULL; if (execvp((char *) ec->cmd.data, args) == -1) { exit(1); } break; default: /* parent */ close(pipefd[1]); e->active = 1; e->pid = pid; e->pipefd = pipefd[0]; if (e->save_pid) { *e->save_pid = pid; } e->dummy_conn.fd = e->pipefd; e->dummy_conn.data = e; e->dummy_conn.read = &e->read_evt; e->dummy_conn.write = &e->write_evt; e->read_evt.data = &e->dummy_conn; e->write_evt.data = &e->dummy_conn; e->read_evt.log = e->log; e->read_evt.handler = ngx_rtmp_exec_child_dead; if (ngx_add_event(&e->read_evt, NGX_READ_EVENT, 0) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, "exec: failed to add child control event"); } ngx_log_debug2(NGX_LOG_DEBUG_RTMP, e->log, 0, "exec: child '%V' started pid=%i", &ec->cmd, (ngx_int_t) pid); break; } #endif /* NGX_WIN32 */ return NGX_OK; }
subscriber_t *websocket_subscriber_create(ngx_http_request_t *r, nchan_msg_id_t *msg_id) { ngx_buf_t *b; nchan_loc_conf_t *cf = ngx_http_get_module_loc_conf(r, nchan_module); DBG("create for req %p", r); full_subscriber_t *fsub; if((fsub = ngx_alloc(sizeof(*fsub), ngx_cycle->log)) == NULL) { ERR("Unable to allocate"); return NULL; } ngx_memcpy(&fsub->sub, &new_websocket_sub, sizeof(new_websocket_sub)); fsub->request = r; fsub->cln = NULL; fsub->finalize_request = 0; fsub->holding = 0; fsub->shook_hands = 0; fsub->sub.cf = ngx_http_get_module_loc_conf(r, nchan_module); if(msg_id) { fsub->sub.last_msg_id.time = msg_id->time; fsub->sub.last_msg_id.tag = msg_id->tag; } ngx_memzero(&fsub->timeout_ev, sizeof(fsub->timeout_ev)); fsub->timeout_handler = empty_handler; fsub->timeout_handler_data = NULL; fsub->dequeue_handler = empty_handler; fsub->dequeue_handler_data = NULL; fsub->already_enqueued = 0; fsub->awaiting_destruction = 0; fsub->reserved = 0; //initialize reusable chains and bufs ngx_memzero(&fsub->hdr_buf, sizeof(fsub->hdr_buf)); ngx_memzero(&fsub->msg_buf, sizeof(fsub->msg_buf)); //space for frame header fsub->hdr_buf.start = ngx_pcalloc(r->pool, WEBSOCKET_FRAME_HEADER_MAX_LENGTH); fsub->hdr_chain.buf = &fsub->hdr_buf; fsub->hdr_chain.next = &fsub->msg_chain; fsub->msg_chain.buf = &fsub->msg_buf; fsub->msg_chain.next = NULL; //what should the buffers look like? b = &fsub->msg_buf; b->last_buf = 1; b->last_in_chain = 1; b->flush = 1; b->memory = 1; b->temporary = 0; if(cf->pub.websocket) { fsub->publish_channel_id = nchan_get_channel_id(r, PUB, 0); } websocket_init_frame(&fsub->frame); fsub->owner = memstore_slot(); //http request sudden close cleanup if((fsub->cln = ngx_http_cleanup_add(r, 0)) == NULL) { ERR("Unable to add request cleanup for websocket subscriber"); return NULL; } fsub->cln->data = fsub; fsub->cln->handler = (ngx_http_cleanup_pt )sudden_abort_handler; DBG("%p created for request %p", &fsub->sub, r); ngx_http_set_ctx(r, fsub, nchan_module); //gonna need this for recv return &fsub->sub; }
static ngx_int_t spool_fetch_msg_callback(nchan_msg_status_t findmsg_status, nchan_msg_t *msg, fetchmsg_data_t *data) { nchan_msg_status_t prev_status; subscriber_pool_t *spool, *nuspool; channel_spooler_t *spl = data->spooler; int free_msg_id = 1; if(spl && data == spl->fetchmsg_cb_data_list) { spl->fetchmsg_cb_data_list = data->next; } if(data->next) { data->next->prev = data->prev; } if(data->prev) { data->prev->next = data->next; } if(spl == NULL) { //channel already deleted nchan_free_msg_id(&data->msgid); ngx_free(data); return NGX_OK; } if(spl->handlers->get_message_finish) { spl->handlers->get_message_finish(spl, spl->handlers_privdata); } if((spool = find_spool(spl, &data->msgid)) == NULL) { DBG("spool for msgid %V not found. discarding getmsg callback response.", msgid_to_str(&data->msgid)); nchan_free_msg_id(&data->msgid); ngx_free(data); return NGX_ERROR; } prev_status = spool->msg_status; switch(findmsg_status) { case MSG_FOUND: spool->msg_status = findmsg_status; DBG("fetchmsg callback for spool %p msg FOUND %p %V", spool, msg, msgid_to_str(&msg->id)); assert(msg != NULL); spool->msg = msg; spool_respond_general(spool, spool->msg, 0, NULL, 0); spool_nextmsg(spool, &msg->id); break; case MSG_EXPECTED: // ♫ It's gonna be the future soon ♫ if(spool->id.time == NCHAN_NTH_MSGID_TIME) { //wait for message in the NEWEST_ID spool nchan_msg_id_t newest_id = NCHAN_NEWEST_MSGID; spool_nextmsg(spool, &newest_id); } else { spool->msg_status = findmsg_status; DBG("fetchmsg callback for spool %p msg EXPECTED", spool); spool_respond_general(spool, NULL, NGX_HTTP_NO_CONTENT, NULL, 0); assert(msg == NULL); spool->msg = NULL; } break; case MSG_NORESPONSE: if(prev_status == MSG_PENDING) { spool->msg_status = MSG_INVALID; if(spool->sub_count > 0) { nomsg_retry_data_t *retry_data = ngx_alloc(sizeof(*retry_data), ngx_cycle->log); retry_data->spooler = spl; free_msg_id = 0; retry_data->msg_id = data->msgid; spooler_add_timer(spl, NCHAN_MSG_NORESPONSE_RETRY_TIME, spool_fetch_msg_noresponse_retry_callback, spool_fetch_msg_noresponse_retry_cancel, retry_data); } } break; case MSG_NOTFOUND: if(spl->fetching_strategy == FETCH_IGNORE_MSG_NOTFOUND) { spool->msg_status = prev_status; break; } case MSG_EXPIRED: //is this right? //TODO: maybe message-expired notification spool->msg_status = findmsg_status; spool_respond_general(spool, NULL, NGX_HTTP_NO_CONTENT, NULL, 0); nuspool = get_spool(spool->spooler, &oldest_msg_id); if(spool != nuspool) { spool_transfer_subscribers(spool, nuspool, 1); destroy_spool(spool); } else { ERR("Unexpected spool == nuspool during spool fetch_msg_callback. This is weird, please report this to the developers. findmsg_status: %i", findmsg_status); assert(0); } break; case MSG_PENDING: ERR("spool %p set status to MSG_PENDING", spool); break; default: assert(0); break; } if(free_msg_id) { nchan_free_msg_id(&data->msgid); } ngx_free(data); return NGX_OK; }
ngx_shm_zone_t *zone; shmem_t *shm; shm_size = ngx_align(shm_size, ngx_pagesize); if (shm_size < 8 * ngx_pagesize) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "The push_max_reserved_memory value must be at least %udKiB", (8 * ngx_pagesize) >> 10); shm_size = 8 * ngx_pagesize; } /* if(nchan_shm_zone && nchan_shm_zone->shm.size != shm_size) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "Cannot change memory area size without restart, ignoring change"); } */ ngx_conf_log_error(NGX_LOG_INFO, cf, 0, "Using %udKiB of shared memory for nchan", shm_size >> 10); shm = ngx_alloc(sizeof(*shm), ngx_cycle->log); zone = ngx_shared_memory_add(cf, name, shm_size, &nchan_module); if (zone == NULL || shm == NULL) { return NULL; } shm->zone = zone; zone->init = init; zone->data = (void *) 1; return shm; } ngx_int_t shm_init(shmem_t *shm) { #if (DEBUG_SHM_ALLOC == 1) ngx_slab_pool_t *shpool = SHPOOL(shm); ngx_log_error(NGX_LOG_WARN, ngx_cycle->log, 0, "nchan_shpool start %p size %i", shpool->start, (u_char *)shpool->end - (u_char *)shpool->start);
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const #endif u_char *p; int n; size_t len; time_t now, valid; ngx_str_t response; X509_STORE *store; STACK_OF(X509) *chain; OCSP_CERTID *id; OCSP_RESPONSE *ocsp; OCSP_BASICRESP *basic; ngx_ssl_stapling_t *staple; ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; staple = ctx->data; now = ngx_time(); ocsp = NULL; basic = NULL; id = NULL; if (ctx->code != 200) { goto error; } /* check the response */ len = ctx->response->last - ctx->response->pos; p = ctx->response->pos; ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (ocsp == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "d2i_OCSP_RESPONSE() failed"); goto error; } n = OCSP_response_status(ocsp); if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "OCSP response not successful (%d: %s)", n, OCSP_response_status_str(n)); goto error; } basic = OCSP_response_get1_basic(ocsp); if (basic == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_response_get1_basic() failed"); goto error; } store = SSL_CTX_get_cert_store(staple->ssl_ctx); if (store == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "SSL_CTX_get_cert_store() failed"); goto error; } #ifdef SSL_CTRL_SELECT_CURRENT_CERT /* OpenSSL 1.0.2+ */ SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert); #endif #ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS /* OpenSSL 1.0.1+ */ SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); #else chain = staple->ssl_ctx->extra_certs; #endif if (OCSP_basic_verify(basic, chain, store, staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_basic_verify() failed"); goto error; } id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (id == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "OCSP_cert_to_id() failed"); goto error; } if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, &thisupdate, &nextupdate) != 1) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status not found in the OCSP response"); goto error; } if (n != V_OCSP_CERTSTATUS_GOOD) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status \"%s\" in the OCSP response", OCSP_cert_status_str(n)); goto error; } if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_check_validity() failed"); goto error; } if (nextupdate) { valid = ngx_ssl_stapling_time(nextupdate); if (valid == (time_t) NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "invalid nextUpdate time in certificate status"); goto error; } } else { valid = NGX_MAX_TIME_T_VALUE; } OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(ocsp); id = NULL; basic = NULL; ocsp = NULL; /* copy the response to memory not in ctx->pool */ response.len = len; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { goto error; } ngx_memcpy(response.data, ctx->response->pos, response.len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp response, %s, %uz", OCSP_cert_status_str(n), response.len); if (staple->staple.data) { ngx_free(staple->staple.data); } staple->staple = response; staple->valid = valid; /* * refresh before the response expires, * but not earlier than in 5 minutes, and at least in an hour */ staple->loading = 0; staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); ngx_ssl_ocsp_done(ctx); return; error: staple->loading = 0; staple->refresh = now + 300; if (id) { OCSP_CERTID_free(id); } if (basic) { OCSP_BASICRESP_free(basic); } if (ocsp) { OCSP_RESPONSE_free(ocsp); } ngx_ssl_ocsp_done(ctx); }