aboutsummaryrefslogtreecommitdiffstats
path: root/app/nginx/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'app/nginx/src/core')
-rw-r--r--app/nginx/src/core/nginx.c1583
-rw-r--r--app/nginx/src/core/nginx.h26
-rw-r--r--app/nginx/src/core/ngx_array.c141
-rw-r--r--app/nginx/src/core/ngx_array.h53
-rw-r--r--app/nginx/src/core/ngx_buf.c313
-rw-r--r--app/nginx/src/core/ngx_buf.h170
-rw-r--r--app/nginx/src/core/ngx_conf_file.c1479
-rw-r--r--app/nginx/src/core/ngx_conf_file.h295
-rw-r--r--app/nginx/src/core/ngx_config.h145
-rw-r--r--app/nginx/src/core/ngx_connection.c1404
-rw-r--r--app/nginx/src/core/ngx_connection.h224
-rw-r--r--app/nginx/src/core/ngx_core.h111
-rw-r--r--app/nginx/src/core/ngx_cpuinfo.c139
-rw-r--r--app/nginx/src/core/ngx_crc.h39
-rw-r--r--app/nginx/src/core/ngx_crc32.c129
-rw-r--r--app/nginx/src/core/ngx_crc32.h79
-rw-r--r--app/nginx/src/core/ngx_crypt.c270
-rw-r--r--app/nginx/src/core/ngx_crypt.h20
-rw-r--r--app/nginx/src/core/ngx_cycle.c1384
-rw-r--r--app/nginx/src/core/ngx_cycle.h144
-rw-r--r--app/nginx/src/core/ngx_file.c1127
-rw-r--r--app/nginx/src/core/ngx_file.h164
-rw-r--r--app/nginx/src/core/ngx_hash.c988
-rw-r--r--app/nginx/src/core/ngx_hash.h122
-rw-r--r--app/nginx/src/core/ngx_inet.c1493
-rw-r--r--app/nginx/src/core/ngx_inet.h129
-rw-r--r--app/nginx/src/core/ngx_list.c63
-rw-r--r--app/nginx/src/core/ngx_list.h83
-rw-r--r--app/nginx/src/core/ngx_log.c755
-rw-r--r--app/nginx/src/core/ngx_log.h268
-rw-r--r--app/nginx/src/core/ngx_md5.c283
-rw-r--r--app/nginx/src/core/ngx_md5.h28
-rw-r--r--app/nginx/src/core/ngx_module.c360
-rw-r--r--app/nginx/src/core/ngx_module.h283
-rw-r--r--app/nginx/src/core/ngx_murmurhash.c50
-rw-r--r--app/nginx/src/core/ngx_murmurhash.h19
-rw-r--r--app/nginx/src/core/ngx_open_file_cache.c1253
-rw-r--r--app/nginx/src/core/ngx_open_file_cache.h129
-rw-r--r--app/nginx/src/core/ngx_output_chain.c767
-rw-r--r--app/nginx/src/core/ngx_palloc.c430
-rw-r--r--app/nginx/src/core/ngx_palloc.h95
-rw-r--r--app/nginx/src/core/ngx_parse.c283
-rw-r--r--app/nginx/src/core/ngx_parse.h21
-rw-r--r--app/nginx/src/core/ngx_parse_time.c276
-rw-r--r--app/nginx/src/core/ngx_parse_time.h22
-rw-r--r--app/nginx/src/core/ngx_proxy_protocol.c168
-rw-r--r--app/nginx/src/core/ngx_proxy_protocol.h25
-rw-r--r--app/nginx/src/core/ngx_queue.c80
-rw-r--r--app/nginx/src/core/ngx_queue.h112
-rw-r--r--app/nginx/src/core/ngx_radix_tree.c488
-rw-r--r--app/nginx/src/core/ngx_radix_tree.h55
-rw-r--r--app/nginx/src/core/ngx_rbtree.c409
-rw-r--r--app/nginx/src/core/ngx_rbtree.h84
-rw-r--r--app/nginx/src/core/ngx_regex.c435
-rw-r--r--app/nginx/src/core/ngx_regex.h60
-rw-r--r--app/nginx/src/core/ngx_resolver.c4662
-rw-r--r--app/nginx/src/core/ngx_resolver.h238
-rw-r--r--app/nginx/src/core/ngx_rwlock.c120
-rw-r--r--app/nginx/src/core/ngx_rwlock.h21
-rw-r--r--app/nginx/src/core/ngx_sha1.c294
-rw-r--r--app/nginx/src/core/ngx_sha1.h28
-rw-r--r--app/nginx/src/core/ngx_shmtx.c310
-rw-r--r--app/nginx/src/core/ngx_shmtx.h49
-rw-r--r--app/nginx/src/core/ngx_slab.c806
-rw-r--r--app/nginx/src/core/ngx_slab.h71
-rw-r--r--app/nginx/src/core/ngx_spinlock.c53
-rw-r--r--app/nginx/src/core/ngx_string.c1976
-rw-r--r--app/nginx/src/core/ngx_string.h234
-rw-r--r--app/nginx/src/core/ngx_syslog.c382
-rw-r--r--app/nginx/src/core/ngx_syslog.h31
-rw-r--r--app/nginx/src/core/ngx_thread_pool.c641
-rw-r--r--app/nginx/src/core/ngx_thread_pool.h36
-rw-r--r--app/nginx/src/core/ngx_times.c428
-rw-r--r--app/nginx/src/core/ngx_times.h52
74 files changed, 29987 insertions, 0 deletions
diff --git a/app/nginx/src/core/nginx.c b/app/nginx/src/core/nginx.c
new file mode 100644
index 0000000..abaa50d
--- /dev/null
+++ b/app/nginx/src/core/nginx.c
@@ -0,0 +1,1583 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <nginx.h>
+
+
+static void ngx_show_version_info(void);
+static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle);
+static void ngx_cleanup_environment(void *data);
+static ngx_int_t ngx_get_options(int argc, char *const *argv);
+static ngx_int_t ngx_process_options(ngx_cycle_t *cycle);
+static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv);
+static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
+static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf);
+static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+#if (NGX_HAVE_DLOPEN)
+static void ngx_unload_module(void *data);
+#endif
+
+
+static ngx_conf_enum_t ngx_debug_points[] = {
+ { ngx_string("stop"), NGX_DEBUG_POINTS_STOP },
+ { ngx_string("abort"), NGX_DEBUG_POINTS_ABORT },
+ { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t ngx_core_commands[] = {
+
+ { ngx_string("daemon"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ 0,
+ offsetof(ngx_core_conf_t, daemon),
+ NULL },
+
+ { ngx_string("master_process"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ 0,
+ offsetof(ngx_core_conf_t, master),
+ NULL },
+
+ { ngx_string("timer_resolution"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ 0,
+ offsetof(ngx_core_conf_t, timer_resolution),
+ NULL },
+
+ { ngx_string("pid"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ 0,
+ offsetof(ngx_core_conf_t, pid),
+ NULL },
+
+ { ngx_string("lock_file"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ 0,
+ offsetof(ngx_core_conf_t, lock_file),
+ NULL },
+
+ { ngx_string("worker_processes"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_set_worker_processes,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("debug_points"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ 0,
+ offsetof(ngx_core_conf_t, debug_points),
+ &ngx_debug_points },
+
+ { ngx_string("user"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE12,
+ ngx_set_user,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("worker_priority"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_set_priority,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("worker_cpu_affinity"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE,
+ ngx_set_cpu_affinity,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("worker_rlimit_nofile"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ 0,
+ offsetof(ngx_core_conf_t, rlimit_nofile),
+ NULL },
+
+ { ngx_string("worker_rlimit_core"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_off_slot,
+ 0,
+ offsetof(ngx_core_conf_t, rlimit_core),
+ NULL },
+
+ { ngx_string("worker_shutdown_timeout"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ 0,
+ offsetof(ngx_core_conf_t, shutdown_timeout),
+ NULL },
+
+ { ngx_string("working_directory"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ 0,
+ offsetof(ngx_core_conf_t, working_directory),
+ NULL },
+
+ { ngx_string("env"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_set_env,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("load_module"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+ ngx_load_module,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_core_module_ctx = {
+ ngx_string("core"),
+ ngx_core_module_create_conf,
+ ngx_core_module_init_conf
+};
+
+
+ngx_module_t ngx_core_module = {
+ NGX_MODULE_V1,
+ &ngx_core_module_ctx, /* module context */
+ ngx_core_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_uint_t ngx_show_help;
+static ngx_uint_t ngx_show_version;
+static ngx_uint_t ngx_show_configure;
+static u_char *ngx_prefix;
+static u_char *ngx_conf_file;
+static u_char *ngx_conf_params;
+static char *ngx_signal;
+
+
+static char **ngx_os_environ;
+
+
+int ngx_cdecl
+main(int argc, char *const *argv)
+{
+ ngx_buf_t *b;
+ ngx_log_t *log;
+ ngx_uint_t i;
+ ngx_cycle_t *cycle, init_cycle;
+ ngx_conf_dump_t *cd;
+ ngx_core_conf_t *ccf;
+
+ ngx_debug_init();
+
+ if (ngx_strerror_init() != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_get_options(argc, argv) != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_show_version) {
+ ngx_show_version_info();
+
+ if (!ngx_test_config) {
+ return 0;
+ }
+ }
+
+ /* TODO */ ngx_max_sockets = -1;
+
+ ngx_time_init();
+
+#if (NGX_PCRE)
+ ngx_regex_init();
+#endif
+
+ ngx_pid = ngx_getpid();
+
+ log = ngx_log_init(ngx_prefix);
+ if (log == NULL) {
+ return 1;
+ }
+
+ /* STUB */
+#if (NGX_OPENSSL)
+ ngx_ssl_init(log);
+#endif
+
+ /*
+ * init_cycle->log is required for signal handlers and
+ * ngx_process_options()
+ */
+
+ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
+ init_cycle.log = log;
+ ngx_cycle = &init_cycle;
+
+ init_cycle.pool = ngx_create_pool(1024, log);
+ if (init_cycle.pool == NULL) {
+ return 1;
+ }
+
+ if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_process_options(&init_cycle) != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_os_init(log) != NGX_OK) {
+ return 1;
+ }
+
+ /*
+ * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
+ */
+
+ if (ngx_crc32_table_init() != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_preinit_modules() != NGX_OK) {
+ return 1;
+ }
+
+ cycle = ngx_init_cycle(&init_cycle);
+ if (cycle == NULL) {
+ if (ngx_test_config) {
+ ngx_log_stderr(0, "configuration file %s test failed",
+ init_cycle.conf_file.data);
+ }
+
+ return 1;
+ }
+
+ if (ngx_test_config) {
+ if (!ngx_quiet_mode) {
+ ngx_log_stderr(0, "configuration file %s test is successful",
+ cycle->conf_file.data);
+ }
+
+ if (ngx_dump_config) {
+ cd = cycle->config_dump.elts;
+
+ for (i = 0; i < cycle->config_dump.nelts; i++) {
+
+ ngx_write_stdout("# configuration file ");
+ (void) ngx_write_fd(ngx_stdout, cd[i].name.data,
+ cd[i].name.len);
+ ngx_write_stdout(":" NGX_LINEFEED);
+
+ b = cd[i].buffer;
+
+ (void) ngx_write_fd(ngx_stdout, b->pos, b->last - b->pos);
+ ngx_write_stdout(NGX_LINEFEED);
+ }
+ }
+
+ return 0;
+ }
+
+ if (ngx_signal) {
+ return ngx_signal_process(cycle, ngx_signal);
+ }
+
+ ngx_os_status(cycle->log);
+
+ ngx_cycle = cycle;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) {
+ ngx_process = NGX_PROCESS_MASTER;
+ }
+
+#if !(NGX_WIN32)
+
+ if (ngx_init_signals(cycle->log) != NGX_OK) {
+ return 1;
+ }
+
+ if (!ngx_inherited && ccf->daemon) {
+ if (ngx_daemon(cycle->log) != NGX_OK) {
+ return 1;
+ }
+
+ ngx_daemonized = 1;
+ }
+
+ if (ngx_inherited) {
+ ngx_daemonized = 1;
+ }
+
+#endif
+
+ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
+ return 1;
+ }
+
+ if (ngx_log_redirect_stderr(cycle) != NGX_OK) {
+ return 1;
+ }
+
+ if (log->file->fd != ngx_stderr) {
+ if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_close_file_n " built-in log failed");
+ }
+ }
+
+ ngx_use_stderr = 0;
+
+ if (ngx_process == NGX_PROCESS_SINGLE) {
+ ngx_single_process_cycle(cycle);
+
+ } else {
+ ngx_master_process_cycle(cycle);
+ }
+
+ return 0;
+}
+
+
+static void
+ngx_show_version_info(void)
+{
+ ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED);
+
+ if (ngx_show_help) {
+ ngx_write_stderr(
+ "Usage: nginx [-?hvVtTq] [-s signal] [-c filename] "
+ "[-p prefix] [-g directives]" NGX_LINEFEED
+ NGX_LINEFEED
+ "Options:" NGX_LINEFEED
+ " -?,-h : this help" NGX_LINEFEED
+ " -v : show version and exit" NGX_LINEFEED
+ " -V : show version and configure options then exit"
+ NGX_LINEFEED
+ " -t : test configuration and exit" NGX_LINEFEED
+ " -T : test configuration, dump it and exit"
+ NGX_LINEFEED
+ " -q : suppress non-error messages "
+ "during configuration testing" NGX_LINEFEED
+ " -s signal : send signal to a master process: "
+ "stop, quit, reopen, reload" NGX_LINEFEED
+#ifdef NGX_PREFIX
+ " -p prefix : set prefix path (default: " NGX_PREFIX ")"
+ NGX_LINEFEED
+#else
+ " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED
+#endif
+ " -c filename : set configuration file (default: " NGX_CONF_PATH
+ ")" NGX_LINEFEED
+ " -g directives : set global directives out of configuration "
+ "file" NGX_LINEFEED NGX_LINEFEED
+ );
+ }
+
+ if (ngx_show_configure) {
+
+#ifdef NGX_COMPILER
+ ngx_write_stderr("built by " NGX_COMPILER NGX_LINEFEED);
+#endif
+
+#if (NGX_SSL)
+ if (ngx_strcmp(ngx_ssl_version(), OPENSSL_VERSION_TEXT) == 0) {
+ ngx_write_stderr("built with " OPENSSL_VERSION_TEXT NGX_LINEFEED);
+ } else {
+ ngx_write_stderr("built with " OPENSSL_VERSION_TEXT
+ " (running with ");
+ ngx_write_stderr((char *) (uintptr_t) ngx_ssl_version());
+ ngx_write_stderr(")" NGX_LINEFEED);
+ }
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ ngx_write_stderr("TLS SNI support enabled" NGX_LINEFEED);
+#else
+ ngx_write_stderr("TLS SNI support disabled" NGX_LINEFEED);
+#endif
+#endif
+
+ ngx_write_stderr("configure arguments:" NGX_CONFIGURE NGX_LINEFEED);
+ }
+}
+
+
+static ngx_int_t
+ngx_add_inherited_sockets(ngx_cycle_t *cycle)
+{
+ u_char *p, *v, *inherited;
+ ngx_int_t s;
+ ngx_listening_t *ls;
+
+ inherited = (u_char *) getenv(NGINX_VAR);
+
+ if (inherited == NULL) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
+ "using inherited sockets from \"%s\"", inherited);
+
+ if (ngx_array_init(&cycle->listening, cycle->pool, 10,
+ sizeof(ngx_listening_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ for (p = inherited, v = p; *p; p++) {
+ if (*p == ':' || *p == ';') {
+ s = ngx_atoi(v, p - v);
+ if (s == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "invalid socket number \"%s\" in " NGINX_VAR
+ " environment variable, ignoring the rest"
+ " of the variable", v);
+ break;
+ }
+
+ v = p + 1;
+
+ ls = ngx_array_push(&cycle->listening);
+ if (ls == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(ls, sizeof(ngx_listening_t));
+
+ ls->fd = (ngx_socket_t) s;
+ }
+ }
+
+ if (v != p) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "invalid socket number \"%s\" in " NGINX_VAR
+ " environment variable, ignoring", v);
+ }
+
+ ngx_inherited = 1;
+
+ return ngx_set_inherited_sockets(cycle);
+}
+
+
+char **
+ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last)
+{
+ char **p, **env;
+ ngx_str_t *var;
+ ngx_uint_t i, n;
+ ngx_core_conf_t *ccf;
+ ngx_pool_cleanup_t *cln;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (last == NULL && ccf->environment) {
+ return ccf->environment;
+ }
+
+ var = ccf->env.elts;
+
+ for (i = 0; i < ccf->env.nelts; i++) {
+ if (ngx_strcmp(var[i].data, "TZ") == 0
+ || ngx_strncmp(var[i].data, "TZ=", 3) == 0)
+ {
+ goto tz_found;
+ }
+ }
+
+ var = ngx_array_push(&ccf->env);
+ if (var == NULL) {
+ return NULL;
+ }
+
+ var->len = 2;
+ var->data = (u_char *) "TZ";
+
+ var = ccf->env.elts;
+
+tz_found:
+
+ n = 0;
+
+ for (i = 0; i < ccf->env.nelts; i++) {
+
+ if (var[i].data[var[i].len] == '=') {
+ n++;
+ continue;
+ }
+
+ for (p = ngx_os_environ; *p; p++) {
+
+ if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
+ && (*p)[var[i].len] == '=')
+ {
+ n++;
+ break;
+ }
+ }
+ }
+
+ if (last) {
+ env = ngx_alloc((*last + n + 1) * sizeof(char *), cycle->log);
+ if (env == NULL) {
+ return NULL;
+ }
+
+ *last = n;
+
+ } else {
+ cln = ngx_pool_cleanup_add(cycle->pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ env = ngx_alloc((n + 1) * sizeof(char *), cycle->log);
+ if (env == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_cleanup_environment;
+ cln->data = env;
+ }
+
+ n = 0;
+
+ for (i = 0; i < ccf->env.nelts; i++) {
+
+ if (var[i].data[var[i].len] == '=') {
+ env[n++] = (char *) var[i].data;
+ continue;
+ }
+
+ for (p = ngx_os_environ; *p; p++) {
+
+ if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
+ && (*p)[var[i].len] == '=')
+ {
+ env[n++] = *p;
+ break;
+ }
+ }
+ }
+
+ env[n] = NULL;
+
+ if (last == NULL) {
+ ccf->environment = env;
+ environ = env;
+ }
+
+ return env;
+}
+
+
+static void
+ngx_cleanup_environment(void *data)
+{
+ char **env = data;
+
+ if (environ == env) {
+
+ /*
+ * if the environment is still used, as it happens on exit,
+ * the only option is to leak it
+ */
+
+ return;
+ }
+
+ ngx_free(env);
+}
+
+
+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 ngx_int_t
+ngx_get_options(int argc, char *const *argv)
+{
+ u_char *p;
+ ngx_int_t i;
+
+ for (i = 1; i < argc; i++) {
+
+ p = (u_char *) argv[i];
+
+ if (*p++ != '-') {
+ ngx_log_stderr(0, "invalid option: \"%s\"", argv[i]);
+ return NGX_ERROR;
+ }
+
+ while (*p) {
+
+ switch (*p++) {
+
+ case '?':
+ case 'h':
+ ngx_show_version = 1;
+ ngx_show_help = 1;
+ break;
+
+ case 'v':
+ ngx_show_version = 1;
+ break;
+
+ case 'V':
+ ngx_show_version = 1;
+ ngx_show_configure = 1;
+ break;
+
+ case 't':
+ ngx_test_config = 1;
+ break;
+
+ case 'T':
+ ngx_test_config = 1;
+ ngx_dump_config = 1;
+ break;
+
+ case 'q':
+ ngx_quiet_mode = 1;
+ break;
+
+ case 'p':
+ if (*p) {
+ ngx_prefix = p;
+ goto next;
+ }
+
+ if (argv[++i]) {
+ ngx_prefix = (u_char *) argv[i];
+ goto next;
+ }
+
+ ngx_log_stderr(0, "option \"-p\" requires directory name");
+ return NGX_ERROR;
+
+ case 'c':
+ if (*p) {
+ ngx_conf_file = p;
+ goto next;
+ }
+
+ if (argv[++i]) {
+ ngx_conf_file = (u_char *) argv[i];
+ goto next;
+ }
+
+ ngx_log_stderr(0, "option \"-c\" requires file name");
+ return NGX_ERROR;
+
+ case 'g':
+ if (*p) {
+ ngx_conf_params = p;
+ goto next;
+ }
+
+ if (argv[++i]) {
+ ngx_conf_params = (u_char *) argv[i];
+ goto next;
+ }
+
+ ngx_log_stderr(0, "option \"-g\" requires parameter");
+ return NGX_ERROR;
+
+ case 's':
+ if (*p) {
+ ngx_signal = (char *) p;
+
+ } else if (argv[++i]) {
+ ngx_signal = argv[i];
+
+ } else {
+ ngx_log_stderr(0, "option \"-s\" requires parameter");
+ return NGX_ERROR;
+ }
+
+ if (ngx_strcmp(ngx_signal, "stop") == 0
+ || ngx_strcmp(ngx_signal, "quit") == 0
+ || ngx_strcmp(ngx_signal, "reopen") == 0
+ || ngx_strcmp(ngx_signal, "reload") == 0)
+ {
+ ngx_process = NGX_PROCESS_SIGNALLER;
+ goto next;
+ }
+
+ ngx_log_stderr(0, "invalid option: \"-s %s\"", ngx_signal);
+ return NGX_ERROR;
+
+ default:
+ ngx_log_stderr(0, "invalid option: \"%c\"", *(p - 1));
+ return NGX_ERROR;
+ }
+ }
+
+ next:
+
+ continue;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv)
+{
+#if (NGX_FREEBSD)
+
+ ngx_os_argv = (char **) argv;
+ ngx_argc = argc;
+ ngx_argv = (char **) argv;
+
+#else
+ size_t len;
+ ngx_int_t i;
+
+ ngx_os_argv = (char **) argv;
+ ngx_argc = argc;
+
+ ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log);
+ if (ngx_argv == NULL) {
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < argc; i++) {
+ len = ngx_strlen(argv[i]) + 1;
+
+ ngx_argv[i] = ngx_alloc(len, cycle->log);
+ if (ngx_argv[i] == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn((u_char *) ngx_argv[i], (u_char *) argv[i], len);
+ }
+
+ ngx_argv[i] = NULL;
+
+#endif
+
+ ngx_os_environ = environ;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_process_options(ngx_cycle_t *cycle)
+{
+ u_char *p;
+ size_t len;
+
+ if (ngx_prefix) {
+ len = ngx_strlen(ngx_prefix);
+ p = ngx_prefix;
+
+ if (len && !ngx_path_separator(p[len - 1])) {
+ p = ngx_pnalloc(cycle->pool, len + 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(p, ngx_prefix, len);
+ p[len++] = '/';
+ }
+
+ cycle->conf_prefix.len = len;
+ cycle->conf_prefix.data = p;
+ cycle->prefix.len = len;
+ cycle->prefix.data = p;
+
+ } else {
+
+#ifndef NGX_PREFIX
+
+ p = ngx_pnalloc(cycle->pool, NGX_MAX_PATH);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_getcwd(p, NGX_MAX_PATH) == 0) {
+ ngx_log_stderr(ngx_errno, "[emerg]: " ngx_getcwd_n " failed");
+ return NGX_ERROR;
+ }
+
+ len = ngx_strlen(p);
+
+ p[len++] = '/';
+
+ cycle->conf_prefix.len = len;
+ cycle->conf_prefix.data = p;
+ cycle->prefix.len = len;
+ cycle->prefix.data = p;
+
+#else
+
+#ifdef NGX_CONF_PREFIX
+ ngx_str_set(&cycle->conf_prefix, NGX_CONF_PREFIX);
+#else
+ ngx_str_set(&cycle->conf_prefix, NGX_PREFIX);
+#endif
+ ngx_str_set(&cycle->prefix, NGX_PREFIX);
+
+#endif
+ }
+
+ if (ngx_conf_file) {
+ cycle->conf_file.len = ngx_strlen(ngx_conf_file);
+ cycle->conf_file.data = ngx_conf_file;
+
+ } else {
+ ngx_str_set(&cycle->conf_file, NGX_CONF_PATH);
+ }
+
+ if (ngx_conf_full_name(cycle, &cycle->conf_file, 0) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ for (p = cycle->conf_file.data + cycle->conf_file.len - 1;
+ p > cycle->conf_file.data;
+ p--)
+ {
+ if (ngx_path_separator(*p)) {
+ cycle->conf_prefix.len = p - ngx_cycle->conf_file.data + 1;
+ cycle->conf_prefix.data = ngx_cycle->conf_file.data;
+ break;
+ }
+ }
+
+ if (ngx_conf_params) {
+ cycle->conf_param.len = ngx_strlen(ngx_conf_params);
+ cycle->conf_param.data = ngx_conf_params;
+ }
+
+ if (ngx_test_config) {
+ cycle->log->log_level = NGX_LOG_INFO;
+ }
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_core_module_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_core_conf_t *ccf;
+
+ ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t));
+ if (ccf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc()
+ *
+ * ccf->pid = NULL;
+ * ccf->oldpid = NULL;
+ * ccf->priority = 0;
+ * ccf->cpu_affinity_auto = 0;
+ * ccf->cpu_affinity_n = 0;
+ * ccf->cpu_affinity = NULL;
+ */
+
+ ccf->daemon = NGX_CONF_UNSET;
+ ccf->master = NGX_CONF_UNSET;
+ ccf->timer_resolution = NGX_CONF_UNSET_MSEC;
+ ccf->shutdown_timeout = NGX_CONF_UNSET_MSEC;
+
+ ccf->worker_processes = NGX_CONF_UNSET;
+ ccf->debug_points = NGX_CONF_UNSET;
+
+ ccf->rlimit_nofile = NGX_CONF_UNSET;
+ ccf->rlimit_core = NGX_CONF_UNSET;
+
+ ccf->user = (ngx_uid_t) NGX_CONF_UNSET_UINT;
+ ccf->group = (ngx_gid_t) NGX_CONF_UNSET_UINT;
+
+ if (ngx_array_init(&ccf->env, cycle->pool, 1, sizeof(ngx_str_t))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+
+ return ccf;
+}
+
+
+static char *
+ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_core_conf_t *ccf = conf;
+
+ ngx_conf_init_value(ccf->daemon, 1);
+ ngx_conf_init_value(ccf->master, 1);
+ ngx_conf_init_msec_value(ccf->timer_resolution, 0);
+ ngx_conf_init_msec_value(ccf->shutdown_timeout, 0);
+
+ ngx_conf_init_value(ccf->worker_processes, 1);
+ ngx_conf_init_value(ccf->debug_points, 0);
+
+#if (NGX_HAVE_CPU_AFFINITY)
+
+ if (!ccf->cpu_affinity_auto
+ && ccf->cpu_affinity_n
+ && ccf->cpu_affinity_n != 1
+ && ccf->cpu_affinity_n != (ngx_uint_t) ccf->worker_processes)
+ {
+ ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
+ "the number of \"worker_processes\" is not equal to "
+ "the number of \"worker_cpu_affinity\" masks, "
+ "using last mask for remaining worker processes");
+ }
+
+#endif
+
+
+ if (ccf->pid.len == 0) {
+ ngx_str_set(&ccf->pid, NGX_PID_PATH);
+ }
+
+ if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT);
+
+ ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len);
+ if (ccf->oldpid.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len),
+ NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT));
+
+
+#if !(NGX_WIN32)
+
+ if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) {
+ struct group *grp;
+ struct passwd *pwd;
+
+ ngx_set_errno(0);
+ pwd = getpwnam(NGX_USER);
+ if (pwd == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "getpwnam(\"" NGX_USER "\") failed");
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->username = NGX_USER;
+ ccf->user = pwd->pw_uid;
+
+ ngx_set_errno(0);
+ grp = getgrnam(NGX_GROUP);
+ if (grp == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "getgrnam(\"" NGX_GROUP "\") failed");
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->group = grp->gr_gid;
+ }
+
+
+ if (ccf->lock_file.len == 0) {
+ ngx_str_set(&ccf->lock_file, NGX_LOCK_PATH);
+ }
+
+ if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ {
+ ngx_str_t lock_file;
+
+ lock_file = cycle->old_cycle->lock_file;
+
+ if (lock_file.len) {
+ lock_file.len--;
+
+ if (ccf->lock_file.len != lock_file.len
+ || ngx_strncmp(ccf->lock_file.data, lock_file.data, lock_file.len)
+ != 0)
+ {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "\"lock_file\" could not be changed, ignored");
+ }
+
+ cycle->lock_file.len = lock_file.len + 1;
+ lock_file.len += sizeof(".accept");
+
+ cycle->lock_file.data = ngx_pstrdup(cycle->pool, &lock_file);
+ if (cycle->lock_file.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else {
+ cycle->lock_file.len = ccf->lock_file.len + 1;
+ cycle->lock_file.data = ngx_pnalloc(cycle->pool,
+ ccf->lock_file.len + sizeof(".accept"));
+ if (cycle->lock_file.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memcpy(ngx_cpymem(cycle->lock_file.data, ccf->lock_file.data,
+ ccf->lock_file.len),
+ ".accept", sizeof(".accept"));
+ }
+ }
+
+#endif
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#if (NGX_WIN32)
+
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "\"user\" is not supported, ignored");
+
+ return NGX_CONF_OK;
+
+#else
+
+ ngx_core_conf_t *ccf = conf;
+
+ char *group;
+ struct passwd *pwd;
+ struct group *grp;
+ ngx_str_t *value;
+
+ if (ccf->user != (uid_t) NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ if (geteuid() != 0) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "the \"user\" directive makes sense only "
+ "if the master process runs "
+ "with super-user privileges, ignored");
+ return NGX_CONF_OK;
+ }
+
+ value = cf->args->elts;
+
+ ccf->username = (char *) value[1].data;
+
+ ngx_set_errno(0);
+ pwd = getpwnam((const char *) value[1].data);
+ if (pwd == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ "getpwnam(\"%s\") failed", value[1].data);
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->user = pwd->pw_uid;
+
+ group = (char *) ((cf->args->nelts == 2) ? value[1].data : value[2].data);
+
+ ngx_set_errno(0);
+ grp = getgrnam(group);
+ if (grp == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ "getgrnam(\"%s\") failed", group);
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->group = grp->gr_gid;
+
+ return NGX_CONF_OK;
+
+#endif
+}
+
+
+static char *
+ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_core_conf_t *ccf = conf;
+
+ ngx_str_t *value, *var;
+ ngx_uint_t i;
+
+ var = ngx_array_push(&ccf->env);
+ if (var == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+ *var = value[1];
+
+ for (i = 0; i < value[1].len; i++) {
+
+ if (value[1].data[i] == '=') {
+
+ var->len = i;
+
+ return NGX_CONF_OK;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_core_conf_t *ccf = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t n, minus;
+
+ if (ccf->priority != 0) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (value[1].data[0] == '-') {
+ n = 1;
+ minus = 1;
+
+ } else if (value[1].data[0] == '+') {
+ n = 1;
+ minus = 0;
+
+ } else {
+ n = 0;
+ minus = 0;
+ }
+
+ ccf->priority = ngx_atoi(&value[1].data[n], value[1].len - n);
+ if (ccf->priority == NGX_ERROR) {
+ return "invalid number";
+ }
+
+ if (minus) {
+ ccf->priority = -ccf->priority;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#if (NGX_HAVE_CPU_AFFINITY)
+ ngx_core_conf_t *ccf = conf;
+
+ u_char ch, *p;
+ ngx_str_t *value;
+ ngx_uint_t i, n;
+ ngx_cpuset_t *mask;
+
+ if (ccf->cpu_affinity) {
+ return "is duplicate";
+ }
+
+ mask = ngx_palloc(cf->pool, (cf->args->nelts - 1) * sizeof(ngx_cpuset_t));
+ if (mask == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->cpu_affinity_n = cf->args->nelts - 1;
+ ccf->cpu_affinity = mask;
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "auto") == 0) {
+
+ if (cf->args->nelts > 3) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid number of arguments in "
+ "\"worker_cpu_affinity\" directive");
+ return NGX_CONF_ERROR;
+ }
+
+ ccf->cpu_affinity_auto = 1;
+
+ CPU_ZERO(&mask[0]);
+ for (i = 0; i < (ngx_uint_t) ngx_min(ngx_ncpu, CPU_SETSIZE); i++) {
+ CPU_SET(i, &mask[0]);
+ }
+
+ n = 2;
+
+ } else {
+ n = 1;
+ }
+
+ for ( /* void */ ; n < cf->args->nelts; n++) {
+
+ if (value[n].len > CPU_SETSIZE) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"worker_cpu_affinity\" supports up to %d CPUs only",
+ CPU_SETSIZE);
+ return NGX_CONF_ERROR;
+ }
+
+ i = 0;
+ CPU_ZERO(&mask[n - 1]);
+
+ for (p = value[n].data + value[n].len - 1;
+ p >= value[n].data;
+ p--)
+ {
+ ch = *p;
+
+ if (ch == ' ') {
+ continue;
+ }
+
+ i++;
+
+ if (ch == '0') {
+ continue;
+ }
+
+ if (ch == '1') {
+ CPU_SET(i - 1, &mask[n - 1]);
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid character \"%c\" in \"worker_cpu_affinity\"",
+ ch);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "\"worker_cpu_affinity\" is not supported "
+ "on this platform, ignored");
+#endif
+
+ return NGX_CONF_OK;
+}
+
+
+ngx_cpuset_t *
+ngx_get_cpu_affinity(ngx_uint_t n)
+{
+#if (NGX_HAVE_CPU_AFFINITY)
+ ngx_uint_t i, j;
+ ngx_cpuset_t *mask;
+ ngx_core_conf_t *ccf;
+
+ static ngx_cpuset_t result;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
+ ngx_core_module);
+
+ if (ccf->cpu_affinity == NULL) {
+ return NULL;
+ }
+
+ if (ccf->cpu_affinity_auto) {
+ mask = &ccf->cpu_affinity[ccf->cpu_affinity_n - 1];
+
+ for (i = 0, j = n; /* void */ ; i++) {
+
+ if (CPU_ISSET(i % CPU_SETSIZE, mask) && j-- == 0) {
+ break;
+ }
+
+ if (i == CPU_SETSIZE && j == n) {
+ /* empty mask */
+ return NULL;
+ }
+
+ /* void */
+ }
+
+ CPU_ZERO(&result);
+ CPU_SET(i % CPU_SETSIZE, &result);
+
+ return &result;
+ }
+
+ if (ccf->cpu_affinity_n > n) {
+ return &ccf->cpu_affinity[n];
+ }
+
+ return &ccf->cpu_affinity[ccf->cpu_affinity_n - 1];
+
+#else
+
+ return NULL;
+
+#endif
+}
+
+
+static char *
+ngx_set_worker_processes(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_str_t *value;
+ ngx_core_conf_t *ccf;
+
+ ccf = (ngx_core_conf_t *) conf;
+
+ if (ccf->worker_processes != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "auto") == 0) {
+ ccf->worker_processes = ngx_ncpu;
+ return NGX_CONF_OK;
+ }
+
+ ccf->worker_processes = ngx_atoi(value[1].data, value[1].len);
+
+ if (ccf->worker_processes == NGX_ERROR) {
+ return "invalid value";
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_load_module(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+#if (NGX_HAVE_DLOPEN)
+ void *handle;
+ char **names, **order;
+ ngx_str_t *value, file;
+ ngx_uint_t i;
+ ngx_module_t *module, **modules;
+ ngx_pool_cleanup_t *cln;
+
+ if (cf->cycle->modules_used) {
+ return "is specified too late";
+ }
+
+ value = cf->args->elts;
+
+ file = value[1];
+
+ if (ngx_conf_full_name(cf->cycle, &file, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ cln = ngx_pool_cleanup_add(cf->cycle->pool, 0);
+ if (cln == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ handle = ngx_dlopen(file.data);
+ if (handle == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ ngx_dlopen_n " \"%s\" failed (%s)",
+ file.data, ngx_dlerror());
+ return NGX_CONF_ERROR;
+ }
+
+ cln->handler = ngx_unload_module;
+ cln->data = handle;
+
+ modules = ngx_dlsym(handle, "ngx_modules");
+ if (modules == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ ngx_dlsym_n " \"%V\", \"%s\" failed (%s)",
+ &value[1], "ngx_modules", ngx_dlerror());
+ return NGX_CONF_ERROR;
+ }
+
+ names = ngx_dlsym(handle, "ngx_module_names");
+ if (names == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ ngx_dlsym_n " \"%V\", \"%s\" failed (%s)",
+ &value[1], "ngx_module_names", ngx_dlerror());
+ return NGX_CONF_ERROR;
+ }
+
+ order = ngx_dlsym(handle, "ngx_module_order");
+
+ for (i = 0; modules[i]; i++) {
+ module = modules[i];
+ module->name = names[i];
+
+ if (ngx_add_module(cf, &file, module, order) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0, "module: %s i:%ui",
+ module->name, module->index);
+ }
+
+ return NGX_CONF_OK;
+
+#else
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"load_module\" is not supported "
+ "on this platform");
+ return NGX_CONF_ERROR;
+
+#endif
+}
+
+
+#if (NGX_HAVE_DLOPEN)
+
+static void
+ngx_unload_module(void *data)
+{
+ void *handle = data;
+
+ if (ngx_dlclose(handle) != 0) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ ngx_dlclose_n " failed (%s)", ngx_dlerror());
+ }
+}
+
+#endif
diff --git a/app/nginx/src/core/nginx.h b/app/nginx/src/core/nginx.h
new file mode 100644
index 0000000..5d3112f
--- /dev/null
+++ b/app/nginx/src/core/nginx.h
@@ -0,0 +1,26 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGINX_H_INCLUDED_
+#define _NGINX_H_INCLUDED_
+
+
+#define nginx_version 1011013
+#define NGINX_VERSION "1.11.13"
+#define NGINX_VER "nginx/" NGINX_VERSION
+
+#ifdef NGX_BUILD
+#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
+#else
+#define NGINX_VER_BUILD NGINX_VER
+#endif
+
+#define NGINX_VAR "NGINX"
+#define NGX_OLDPID_EXT ".oldbin"
+
+
+#endif /* _NGINX_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_array.c b/app/nginx/src/core/ngx_array.c
new file mode 100644
index 0000000..4ea226f
--- /dev/null
+++ b/app/nginx/src/core/ngx_array.c
@@ -0,0 +1,141 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_array_t *
+ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size)
+{
+ ngx_array_t *a;
+
+ a = ngx_palloc(p, sizeof(ngx_array_t));
+ if (a == NULL) {
+ return NULL;
+ }
+
+ if (ngx_array_init(a, p, n, size) != NGX_OK) {
+ return NULL;
+ }
+
+ return a;
+}
+
+
+void
+ngx_array_destroy(ngx_array_t *a)
+{
+ ngx_pool_t *p;
+
+ p = a->pool;
+
+ if ((u_char *) a->elts + a->size * a->nalloc == p->d.last) {
+ p->d.last -= a->size * a->nalloc;
+ }
+
+ if ((u_char *) a + sizeof(ngx_array_t) == p->d.last) {
+ p->d.last = (u_char *) a;
+ }
+}
+
+
+void *
+ngx_array_push(ngx_array_t *a)
+{
+ void *elt, *new;
+ size_t size;
+ ngx_pool_t *p;
+
+ if (a->nelts == a->nalloc) {
+
+ /* the array is full */
+
+ size = a->size * a->nalloc;
+
+ p = a->pool;
+
+ if ((u_char *) a->elts + size == p->d.last
+ && p->d.last + a->size <= p->d.end)
+ {
+ /*
+ * the array allocation is the last in the pool
+ * and there is space for new allocation
+ */
+
+ p->d.last += a->size;
+ a->nalloc++;
+
+ } else {
+ /* allocate a new array */
+
+ new = ngx_palloc(p, 2 * size);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(new, a->elts, size);
+ a->elts = new;
+ a->nalloc *= 2;
+ }
+ }
+
+ elt = (u_char *) a->elts + a->size * a->nelts;
+ a->nelts++;
+
+ return elt;
+}
+
+
+void *
+ngx_array_push_n(ngx_array_t *a, ngx_uint_t n)
+{
+ void *elt, *new;
+ size_t size;
+ ngx_uint_t nalloc;
+ ngx_pool_t *p;
+
+ size = n * a->size;
+
+ if (a->nelts + n > a->nalloc) {
+
+ /* the array is full */
+
+ p = a->pool;
+
+ if ((u_char *) a->elts + a->size * a->nalloc == p->d.last
+ && p->d.last + size <= p->d.end)
+ {
+ /*
+ * the array allocation is the last in the pool
+ * and there is space for new allocation
+ */
+
+ p->d.last += size;
+ a->nalloc += n;
+
+ } else {
+ /* allocate a new array */
+
+ nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc);
+
+ new = ngx_palloc(p, nalloc * a->size);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(new, a->elts, a->nelts * a->size);
+ a->elts = new;
+ a->nalloc = nalloc;
+ }
+ }
+
+ elt = (u_char *) a->elts + a->size * a->nelts;
+ a->nelts += n;
+
+ return elt;
+}
diff --git a/app/nginx/src/core/ngx_array.h b/app/nginx/src/core/ngx_array.h
new file mode 100644
index 0000000..a0f2a74
--- /dev/null
+++ b/app/nginx/src/core/ngx_array.h
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_ARRAY_H_INCLUDED_
+#define _NGX_ARRAY_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ void *elts;
+ ngx_uint_t nelts;
+ size_t size;
+ ngx_uint_t nalloc;
+ ngx_pool_t *pool;
+} ngx_array_t;
+
+
+ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size);
+void ngx_array_destroy(ngx_array_t *a);
+void *ngx_array_push(ngx_array_t *a);
+void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n);
+
+
+static ngx_inline ngx_int_t
+ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size)
+{
+ /*
+ * set "array->nelts" before "array->elts", otherwise MSVC thinks
+ * that "array->nelts" may be used without having been initialized
+ */
+
+ array->nelts = 0;
+ array->size = size;
+ array->nalloc = n;
+ array->pool = pool;
+
+ array->elts = ngx_palloc(pool, n * size);
+ if (array->elts == NULL) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+#endif /* _NGX_ARRAY_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_buf.c b/app/nginx/src/core/ngx_buf.c
new file mode 100644
index 0000000..1862a06
--- /dev/null
+++ b/app/nginx/src/core/ngx_buf.c
@@ -0,0 +1,313 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_buf_t *
+ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
+{
+ ngx_buf_t *b;
+
+ b = ngx_calloc_buf(pool);
+ if (b == NULL) {
+ return NULL;
+ }
+
+ b->start = ngx_palloc(pool, size);
+ if (b->start == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_calloc_buf():
+ *
+ * b->file_pos = 0;
+ * b->file_last = 0;
+ * b->file = NULL;
+ * b->shadow = NULL;
+ * b->tag = 0;
+ * and flags
+ */
+
+ b->pos = b->start;
+ b->last = b->start;
+ b->end = b->last + size;
+ b->temporary = 1;
+
+ return b;
+}
+
+
+ngx_chain_t *
+ngx_alloc_chain_link(ngx_pool_t *pool)
+{
+ ngx_chain_t *cl;
+
+ cl = pool->chain;
+
+ if (cl) {
+ pool->chain = cl->next;
+ return cl;
+ }
+
+ cl = ngx_palloc(pool, sizeof(ngx_chain_t));
+ if (cl == NULL) {
+ return NULL;
+ }
+
+ return cl;
+}
+
+
+ngx_chain_t *
+ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
+{
+ u_char *p;
+ ngx_int_t i;
+ ngx_buf_t *b;
+ ngx_chain_t *chain, *cl, **ll;
+
+ p = ngx_palloc(pool, bufs->num * bufs->size);
+ if (p == NULL) {
+ return NULL;
+ }
+
+ ll = &chain;
+
+ for (i = 0; i < bufs->num; i++) {
+
+ b = ngx_calloc_buf(pool);
+ if (b == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_calloc_buf():
+ *
+ * b->file_pos = 0;
+ * b->file_last = 0;
+ * b->file = NULL;
+ * b->shadow = NULL;
+ * b->tag = 0;
+ * and flags
+ *
+ */
+
+ b->pos = p;
+ b->last = p;
+ b->temporary = 1;
+
+ b->start = p;
+ p += bufs->size;
+ b->end = p;
+
+ cl = ngx_alloc_chain_link(pool);
+ if (cl == NULL) {
+ return NULL;
+ }
+
+ cl->buf = b;
+ *ll = cl;
+ ll = &cl->next;
+ }
+
+ *ll = NULL;
+
+ return chain;
+}
+
+
+ngx_int_t
+ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
+{
+ ngx_chain_t *cl, **ll;
+
+ ll = chain;
+
+ for (cl = *chain; cl; cl = cl->next) {
+ ll = &cl->next;
+ }
+
+ while (in) {
+ cl = ngx_alloc_chain_link(pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = in->buf;
+ *ll = cl;
+ ll = &cl->next;
+ in = in->next;
+ }
+
+ *ll = NULL;
+
+ return NGX_OK;
+}
+
+
+ngx_chain_t *
+ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
+{
+ ngx_chain_t *cl;
+
+ if (*free) {
+ cl = *free;
+ *free = cl->next;
+ cl->next = NULL;
+ return cl;
+ }
+
+ cl = ngx_alloc_chain_link(p);
+ if (cl == NULL) {
+ return NULL;
+ }
+
+ cl->buf = ngx_calloc_buf(p);
+ if (cl->buf == NULL) {
+ return NULL;
+ }
+
+ cl->next = NULL;
+
+ return cl;
+}
+
+
+void
+ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
+ ngx_chain_t **out, ngx_buf_tag_t tag)
+{
+ ngx_chain_t *cl;
+
+ if (*out) {
+ if (*busy == NULL) {
+ *busy = *out;
+
+ } else {
+ for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
+
+ cl->next = *out;
+ }
+
+ *out = NULL;
+ }
+
+ while (*busy) {
+ cl = *busy;
+
+ if (ngx_buf_size(cl->buf) != 0) {
+ break;
+ }
+
+ if (cl->buf->tag != tag) {
+ *busy = cl->next;
+ ngx_free_chain(p, cl);
+ continue;
+ }
+
+ cl->buf->pos = cl->buf->start;
+ cl->buf->last = cl->buf->start;
+
+ *busy = cl->next;
+ cl->next = *free;
+ *free = cl;
+ }
+}
+
+
+off_t
+ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
+{
+ off_t total, size, aligned, fprev;
+ ngx_fd_t fd;
+ ngx_chain_t *cl;
+
+ total = 0;
+
+ cl = *in;
+ fd = cl->buf->file->fd;
+
+ do {
+ size = cl->buf->file_last - cl->buf->file_pos;
+
+ if (size > limit - total) {
+ size = limit - total;
+
+ aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
+ & ~((off_t) ngx_pagesize - 1);
+
+ if (aligned <= cl->buf->file_last) {
+ size = aligned - cl->buf->file_pos;
+ }
+
+ total += size;
+ break;
+ }
+
+ total += size;
+ fprev = cl->buf->file_pos + size;
+ cl = cl->next;
+
+ } while (cl
+ && cl->buf->in_file
+ && total < limit
+ && fd == cl->buf->file->fd
+ && fprev == cl->buf->file_pos);
+
+ *in = cl;
+
+ return total;
+}
+
+
+ngx_chain_t *
+ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
+{
+ off_t size;
+
+ for ( /* void */ ; in; in = in->next) {
+
+ if (ngx_buf_special(in->buf)) {
+ continue;
+ }
+
+ if (sent == 0) {
+ break;
+ }
+
+ size = ngx_buf_size(in->buf);
+
+ if (sent >= size) {
+ sent -= size;
+
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos = in->buf->last;
+ }
+
+ if (in->buf->in_file) {
+ in->buf->file_pos = in->buf->file_last;
+ }
+
+ continue;
+ }
+
+ if (ngx_buf_in_memory(in->buf)) {
+ in->buf->pos += (size_t) sent;
+ }
+
+ if (in->buf->in_file) {
+ in->buf->file_pos += sent;
+ }
+
+ break;
+ }
+
+ return in;
+}
diff --git a/app/nginx/src/core/ngx_buf.h b/app/nginx/src/core/ngx_buf.h
new file mode 100644
index 0000000..12781a7
--- /dev/null
+++ b/app/nginx/src/core/ngx_buf.h
@@ -0,0 +1,170 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_BUF_H_INCLUDED_
+#define _NGX_BUF_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef void * ngx_buf_tag_t;
+
+typedef struct ngx_buf_s ngx_buf_t;
+
+struct ngx_buf_s {
+ u_char *pos;
+ u_char *last;
+ off_t file_pos;
+ off_t file_last;
+
+ u_char *start; /* start of buffer */
+ u_char *end; /* end of buffer */
+ ngx_buf_tag_t tag;
+ ngx_file_t *file;
+ ngx_buf_t *shadow;
+
+
+ /* the buf's content could be changed */
+ unsigned temporary:1;
+
+ /*
+ * the buf's content is in a memory cache or in a read only memory
+ * and must not be changed
+ */
+ unsigned memory:1;
+
+ /* the buf's content is mmap()ed and must not be changed */
+ unsigned mmap:1;
+
+ unsigned recycled:1;
+ unsigned in_file:1;
+ unsigned flush:1;
+ unsigned sync:1;
+ unsigned last_buf:1;
+ unsigned last_in_chain:1;
+
+ unsigned last_shadow:1;
+ unsigned temp_file:1;
+
+ /* STUB */ int num;
+};
+
+
+struct ngx_chain_s {
+ ngx_buf_t *buf;
+ ngx_chain_t *next;
+};
+
+
+typedef struct {
+ ngx_int_t num;
+ size_t size;
+} ngx_bufs_t;
+
+
+typedef struct ngx_output_chain_ctx_s ngx_output_chain_ctx_t;
+
+typedef ngx_int_t (*ngx_output_chain_filter_pt)(void *ctx, ngx_chain_t *in);
+
+typedef void (*ngx_output_chain_aio_pt)(ngx_output_chain_ctx_t *ctx,
+ ngx_file_t *file);
+
+struct ngx_output_chain_ctx_s {
+ ngx_buf_t *buf;
+ ngx_chain_t *in;
+ ngx_chain_t *free;
+ ngx_chain_t *busy;
+
+ unsigned sendfile:1;
+ unsigned directio:1;
+ unsigned unaligned:1;
+ unsigned need_in_memory:1;
+ unsigned need_in_temp:1;
+ unsigned aio:1;
+
+#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
+ ngx_output_chain_aio_pt aio_handler;
+#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
+ ssize_t (*aio_preload)(ngx_buf_t *file);
+#endif
+#endif
+
+#if (NGX_THREADS || NGX_COMPAT)
+ ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
+ ngx_file_t *file);
+ ngx_thread_task_t *thread_task;
+#endif
+
+ off_t alignment;
+
+ ngx_pool_t *pool;
+ ngx_int_t allocated;
+ ngx_bufs_t bufs;
+ ngx_buf_tag_t tag;
+
+ ngx_output_chain_filter_pt output_filter;
+ void *filter_ctx;
+};
+
+
+typedef struct {
+ ngx_chain_t *out;
+ ngx_chain_t **last;
+ ngx_connection_t *connection;
+ ngx_pool_t *pool;
+ off_t limit;
+} ngx_chain_writer_ctx_t;
+
+
+#define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR
+
+
+#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap)
+#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file)
+
+#define ngx_buf_special(b) \
+ ((b->flush || b->last_buf || b->sync) \
+ && !ngx_buf_in_memory(b) && !b->in_file)
+
+#define ngx_buf_sync_only(b) \
+ (b->sync \
+ && !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf)
+
+#define ngx_buf_size(b) \
+ (ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \
+ (b->file_last - b->file_pos))
+
+ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
+ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
+
+
+#define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t))
+#define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t))
+
+ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);
+#define ngx_free_chain(pool, cl) \
+ cl->next = pool->chain; \
+ pool->chain = cl
+
+
+
+ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in);
+ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in);
+
+ngx_int_t ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
+ ngx_chain_t *in);
+ngx_chain_t *ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free);
+void ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free,
+ ngx_chain_t **busy, ngx_chain_t **out, ngx_buf_tag_t tag);
+
+off_t ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit);
+
+ngx_chain_t *ngx_chain_update_sent(ngx_chain_t *in, off_t sent);
+
+#endif /* _NGX_BUF_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_conf_file.c b/app/nginx/src/core/ngx_conf_file.c
new file mode 100644
index 0000000..ce8c602
--- /dev/null
+++ b/app/nginx/src/core/ngx_conf_file.c
@@ -0,0 +1,1479 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+#define NGX_CONF_BUFFER 4096
+
+static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename);
+static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);
+static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf);
+static void ngx_conf_flush_files(ngx_cycle_t *cycle);
+
+
+static ngx_command_t ngx_conf_commands[] = {
+
+ { ngx_string("include"),
+ NGX_ANY_CONF|NGX_CONF_TAKE1,
+ ngx_conf_include,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+ngx_module_t ngx_conf_module = {
+ NGX_MODULE_V1,
+ NULL, /* module context */
+ ngx_conf_commands, /* module directives */
+ NGX_CONF_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_conf_flush_files, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+/* The eight fixed arguments */
+
+static ngx_uint_t argument_number[] = {
+ NGX_CONF_NOARGS,
+ NGX_CONF_TAKE1,
+ NGX_CONF_TAKE2,
+ NGX_CONF_TAKE3,
+ NGX_CONF_TAKE4,
+ NGX_CONF_TAKE5,
+ NGX_CONF_TAKE6,
+ NGX_CONF_TAKE7
+};
+
+
+char *
+ngx_conf_param(ngx_conf_t *cf)
+{
+ char *rv;
+ ngx_str_t *param;
+ ngx_buf_t b;
+ ngx_conf_file_t conf_file;
+
+ param = &cf->cycle->conf_param;
+
+ if (param->len == 0) {
+ return NGX_CONF_OK;
+ }
+
+ ngx_memzero(&conf_file, sizeof(ngx_conf_file_t));
+
+ ngx_memzero(&b, sizeof(ngx_buf_t));
+
+ b.start = param->data;
+ b.pos = param->data;
+ b.last = param->data + param->len;
+ b.end = b.last;
+ b.temporary = 1;
+
+ conf_file.file.fd = NGX_INVALID_FILE;
+ conf_file.file.name.data = NULL;
+ conf_file.line = 0;
+
+ cf->conf_file = &conf_file;
+ cf->conf_file->buffer = &b;
+
+ rv = ngx_conf_parse(cf, NULL);
+
+ cf->conf_file = NULL;
+
+ return rv;
+}
+
+
+static ngx_int_t
+ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename)
+{
+ off_t size;
+ u_char *p;
+ uint32_t hash;
+ ngx_buf_t *buf;
+ ngx_str_node_t *sn;
+ ngx_conf_dump_t *cd;
+
+ hash = ngx_crc32_long(filename->data, filename->len);
+
+ sn = ngx_str_rbtree_lookup(&cf->cycle->config_dump_rbtree, filename, hash);
+
+ if (sn) {
+ cf->conf_file->dump = NULL;
+ return NGX_OK;
+ }
+
+ p = ngx_pstrdup(cf->cycle->pool, filename);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ cd = ngx_array_push(&cf->cycle->config_dump);
+ if (cd == NULL) {
+ return NGX_ERROR;
+ }
+
+ size = ngx_file_size(&cf->conf_file->file.info);
+
+ buf = ngx_create_temp_buf(cf->cycle->pool, (size_t) size);
+ if (buf == NULL) {
+ return NGX_ERROR;
+ }
+
+ cd->name.data = p;
+ cd->name.len = filename->len;
+ cd->buffer = buf;
+
+ cf->conf_file->dump = buf;
+
+ sn = ngx_palloc(cf->temp_pool, sizeof(ngx_str_node_t));
+ if (sn == NULL) {
+ return NGX_ERROR;
+ }
+
+ sn->node.key = hash;
+ sn->str = cd->name;
+
+ ngx_rbtree_insert(&cf->cycle->config_dump_rbtree, &sn->node);
+
+ return NGX_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) == 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
+ )
+ {
+ if (ngx_conf_add_dump(cf, filename) != NGX_OK) {
+ goto failed;
+ }
+
+ } else {
+ cf->conf_file->dump = NULL;
+ }
+
+ } 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
+ */
+
+ 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;
+}
+
+
+static ngx_int_t
+ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
+{
+ char *rv;
+ void *conf, **confp;
+ ngx_uint_t i, found;
+ ngx_str_t *name;
+ ngx_command_t *cmd;
+
+ name = cf->args->elts;
+
+ found = 0;
+
+ for (i = 0; cf->cycle->modules[i]; i++) {
+
+ cmd = cf->cycle->modules[i]->commands;
+ if (cmd == NULL) {
+ continue;
+ }
+
+ for ( /* void */ ; cmd->name.len; cmd++) {
+
+ if (name->len != cmd->name.len) {
+ continue;
+ }
+
+ if (ngx_strcmp(name->data, cmd->name.data) != 0) {
+ continue;
+ }
+
+ found = 1;
+
+ if (cf->cycle->modules[i]->type != NGX_CONF_MODULE
+ && cf->cycle->modules[i]->type != cf->module_type)
+ {
+ continue;
+ }
+
+ /* is the directive's location right ? */
+
+ if (!(cmd->type & cf->cmd_type)) {
+ continue;
+ }
+
+ if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "directive \"%s\" is not terminated by \";\"",
+ name->data);
+ return NGX_ERROR;
+ }
+
+ if ((cmd->type & NGX_CONF_BLOCK) && last != NGX_CONF_BLOCK_START) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "directive \"%s\" has no opening \"{\"",
+ name->data);
+ return NGX_ERROR;
+ }
+
+ /* is the directive's argument count right ? */
+
+ if (!(cmd->type & NGX_CONF_ANY)) {
+
+ if (cmd->type & NGX_CONF_FLAG) {
+
+ if (cf->args->nelts != 2) {
+ goto invalid;
+ }
+
+ } else if (cmd->type & NGX_CONF_1MORE) {
+
+ if (cf->args->nelts < 2) {
+ goto invalid;
+ }
+
+ } else if (cmd->type & NGX_CONF_2MORE) {
+
+ if (cf->args->nelts < 3) {
+ goto invalid;
+ }
+
+ } else if (cf->args->nelts > NGX_CONF_MAX_ARGS) {
+
+ goto invalid;
+
+ } else if (!(cmd->type & argument_number[cf->args->nelts - 1]))
+ {
+ goto invalid;
+ }
+ }
+
+ /* set up the directive's configuration context */
+
+ conf = NULL;
+
+ if (cmd->type & NGX_DIRECT_CONF) {
+ conf = ((void **) cf->ctx)[cf->cycle->modules[i]->index];
+
+ } else if (cmd->type & NGX_MAIN_CONF) {
+ conf = &(((void **) cf->ctx)[cf->cycle->modules[i]->index]);
+
+ } else if (cf->ctx) {
+ confp = *(void **) ((char *) cf->ctx + cmd->conf);
+
+ if (confp) {
+ conf = confp[cf->cycle->modules[i]->ctx_index];
+ }
+ }
+
+ rv = cmd->set(cf, cmd, conf);
+
+ if (rv == NGX_CONF_OK) {
+ return NGX_OK;
+ }
+
+ if (rv == NGX_CONF_ERROR) {
+ return NGX_ERROR;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%s\" directive %s", name->data, rv);
+
+ return NGX_ERROR;
+ }
+ }
+
+ if (found) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%s\" directive is not allowed here", name->data);
+
+ return NGX_ERROR;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown directive \"%s\"", name->data);
+
+ return NGX_ERROR;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid number of arguments in \"%s\" directive",
+ name->data);
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_conf_read_token(ngx_conf_t *cf)
+{
+ u_char *start, ch, *src, *dst;
+ off_t file_size;
+ size_t len;
+ ssize_t n, size;
+ ngx_uint_t found, need_space, last_space, sharp_comment, variable;
+ ngx_uint_t quoted, s_quoted, d_quoted, start_line;
+ ngx_str_t *word;
+ ngx_buf_t *b, *dump;
+
+ found = 0;
+ need_space = 0;
+ last_space = 1;
+ sharp_comment = 0;
+ variable = 0;
+ quoted = 0;
+ s_quoted = 0;
+ d_quoted = 0;
+
+ cf->args->nelts = 0;
+ b = cf->conf_file->buffer;
+ dump = cf->conf_file->dump;
+ start = b->pos;
+ start_line = cf->conf_file->line;
+
+ file_size = ngx_file_size(&cf->conf_file->file.info);
+
+ for ( ;; ) {
+
+ if (b->pos >= b->last) {
+
+ if (cf->conf_file->file.offset >= file_size) {
+
+ if (cf->args->nelts > 0 || !last_space) {
+
+ if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unexpected end of parameter, "
+ "expecting \";\"");
+ return NGX_ERROR;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unexpected end of file, "
+ "expecting \";\" or \"}\"");
+ return NGX_ERROR;
+ }
+
+ return NGX_CONF_FILE_DONE;
+ }
+
+ len = b->pos - start;
+
+ if (len == NGX_CONF_BUFFER) {
+ cf->conf_file->line = start_line;
+
+ if (d_quoted) {
+ ch = '"';
+
+ } else if (s_quoted) {
+ ch = '\'';
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "too long parameter \"%*s...\" started",
+ 10, start);
+ return NGX_ERROR;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "too long parameter, probably "
+ "missing terminating \"%c\" character", ch);
+ return NGX_ERROR;
+ }
+
+ if (len) {
+ ngx_memmove(b->start, start, len);
+ }
+
+ size = (ssize_t) (file_size - cf->conf_file->file.offset);
+
+ if (size > b->end - (b->start + len)) {
+ size = b->end - (b->start + len);
+ }
+
+ n = ngx_read_file(&cf->conf_file->file, b->start + len, size,
+ cf->conf_file->file.offset);
+
+ if (n == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (n != size) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ ngx_read_file_n " returned "
+ "only %z bytes instead of %z",
+ n, size);
+ return NGX_ERROR;
+ }
+
+ b->pos = b->start + len;
+ b->last = b->pos + n;
+ start = b->start;
+
+ if (dump) {
+ dump->last = ngx_cpymem(dump->last, b->pos, size);
+ }
+ }
+
+ ch = *b->pos++;
+
+ if (ch == LF) {
+ cf->conf_file->line++;
+
+ if (sharp_comment) {
+ sharp_comment = 0;
+ }
+ }
+
+ if (sharp_comment) {
+ continue;
+ }
+
+ if (quoted) {
+ quoted = 0;
+ continue;
+ }
+
+ if (need_space) {
+ if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
+ last_space = 1;
+ need_space = 0;
+ continue;
+ }
+
+ if (ch == ';') {
+ return NGX_OK;
+ }
+
+ if (ch == '{') {
+ return NGX_CONF_BLOCK_START;
+ }
+
+ if (ch == ')') {
+ last_space = 1;
+ need_space = 0;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unexpected \"%c\"", ch);
+ return NGX_ERROR;
+ }
+ }
+
+ if (last_space) {
+ if (ch == ' ' || ch == '\t' || ch == CR || ch == LF) {
+ continue;
+ }
+
+ start = b->pos - 1;
+ start_line = cf->conf_file->line;
+
+ switch (ch) {
+
+ case ';':
+ case '{':
+ if (cf->args->nelts == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unexpected \"%c\"", ch);
+ return NGX_ERROR;
+ }
+
+ if (ch == '{') {
+ return NGX_CONF_BLOCK_START;
+ }
+
+ return NGX_OK;
+
+ case '}':
+ if (cf->args->nelts != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unexpected \"}\"");
+ return NGX_ERROR;
+ }
+
+ return NGX_CONF_BLOCK_DONE;
+
+ case '#':
+ sharp_comment = 1;
+ continue;
+
+ case '\\':
+ quoted = 1;
+ last_space = 0;
+ continue;
+
+ case '"':
+ start++;
+ d_quoted = 1;
+ last_space = 0;
+ continue;
+
+ case '\'':
+ start++;
+ s_quoted = 1;
+ last_space = 0;
+ continue;
+
+ default:
+ last_space = 0;
+ }
+
+ } else {
+ if (ch == '{' && variable) {
+ continue;
+ }
+
+ variable = 0;
+
+ if (ch == '\\') {
+ quoted = 1;
+ continue;
+ }
+
+ if (ch == '$') {
+ variable = 1;
+ continue;
+ }
+
+ if (d_quoted) {
+ if (ch == '"') {
+ d_quoted = 0;
+ need_space = 1;
+ found = 1;
+ }
+
+ } else if (s_quoted) {
+ if (ch == '\'') {
+ s_quoted = 0;
+ need_space = 1;
+ found = 1;
+ }
+
+ } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF
+ || ch == ';' || ch == '{')
+ {
+ last_space = 1;
+ found = 1;
+ }
+
+ if (found) {
+ word = ngx_array_push(cf->args);
+ if (word == NULL) {
+ return NGX_ERROR;
+ }
+
+ word->data = ngx_pnalloc(cf->pool, b->pos - 1 - start + 1);
+ if (word->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ for (dst = word->data, src = start, len = 0;
+ src < b->pos - 1;
+ len++)
+ {
+ if (*src == '\\') {
+ switch (src[1]) {
+ case '"':
+ case '\'':
+ case '\\':
+ src++;
+ break;
+
+ case 't':
+ *dst++ = '\t';
+ src += 2;
+ continue;
+
+ case 'r':
+ *dst++ = '\r';
+ src += 2;
+ continue;
+
+ case 'n':
+ *dst++ = '\n';
+ src += 2;
+ continue;
+ }
+
+ }
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+ word->len = len;
+
+ if (ch == ';') {
+ return NGX_OK;
+ }
+
+ if (ch == '{') {
+ return NGX_CONF_BLOCK_START;
+ }
+
+ found = 0;
+ }
+ }
+ }
+}
+
+
+char *
+ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *rv;
+ ngx_int_t n;
+ ngx_str_t *value, file, name;
+ ngx_glob_t gl;
+
+ value = cf->args->elts;
+ file = value[1];
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+ if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (strpbrk((char *) file.data, "*?[") == NULL) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+ return ngx_conf_parse(cf, &file);
+ }
+
+ ngx_memzero(&gl, sizeof(ngx_glob_t));
+
+ gl.pattern = file.data;
+ gl.log = cf->log;
+ gl.test = 1;
+
+ if (ngx_open_glob(&gl) != NGX_OK) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ ngx_open_glob_n " \"%s\" failed", file.data);
+ return NGX_CONF_ERROR;
+ }
+
+ rv = NGX_CONF_OK;
+
+ for ( ;; ) {
+ n = ngx_read_glob(&gl, &name);
+
+ if (n != NGX_OK) {
+ break;
+ }
+
+ file.len = name.len++;
+ file.data = ngx_pstrdup(cf->pool, &name);
+ if (file.data == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
+
+ rv = ngx_conf_parse(cf, &file);
+
+ if (rv != NGX_CONF_OK) {
+ break;
+ }
+ }
+
+ ngx_close_glob(&gl);
+
+ return rv;
+}
+
+
+ngx_int_t
+ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, ngx_uint_t conf_prefix)
+{
+ ngx_str_t *prefix;
+
+ prefix = conf_prefix ? &cycle->conf_prefix : &cycle->prefix;
+
+ return ngx_get_full_name(cycle->pool, prefix, name);
+}
+
+
+ngx_open_file_t *
+ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name)
+{
+ ngx_str_t full;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_open_file_t *file;
+
+#if (NGX_SUPPRESS_WARN)
+ ngx_str_null(&full);
+#endif
+
+ if (name->len) {
+ full = *name;
+
+ if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) {
+ return NULL;
+ }
+
+ part = &cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (full.len != file[i].name.len) {
+ continue;
+ }
+
+ if (ngx_strcmp(full.data, file[i].name.data) == 0) {
+ return &file[i];
+ }
+ }
+ }
+
+ file = ngx_list_push(&cycle->open_files);
+ if (file == NULL) {
+ return NULL;
+ }
+
+ if (name->len) {
+ file->fd = NGX_INVALID_FILE;
+ file->name = full;
+
+ } else {
+ file->fd = ngx_stderr;
+ file->name = *name;
+ }
+
+ file->flush = NULL;
+ file->data = NULL;
+
+ return file;
+}
+
+
+static void
+ngx_conf_flush_files(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_open_file_t *file;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "flush files");
+
+ part = &cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (file[i].flush) {
+ file[i].flush(&file[i], cycle->log);
+ }
+ }
+}
+
+
+void ngx_cdecl
+ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
+ const char *fmt, ...)
+{
+ u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
+ va_list args;
+
+ last = errstr + NGX_MAX_CONF_ERRSTR;
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(errstr, last, fmt, args);
+ va_end(args);
+
+ if (err) {
+ p = ngx_log_errno(p, last, err);
+ }
+
+ if (cf->conf_file == NULL) {
+ ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
+ return;
+ }
+
+ if (cf->conf_file->file.fd == NGX_INVALID_FILE) {
+ ngx_log_error(level, cf->log, 0, "%*s in command line",
+ p - errstr, errstr);
+ return;
+ }
+
+ ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
+ p - errstr, errstr,
+ cf->conf_file->file.name.data, cf->conf_file->line);
+}
+
+
+char *
+ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value;
+ ngx_flag_t *fp;
+ ngx_conf_post_t *post;
+
+ fp = (ngx_flag_t *) (p + cmd->offset);
+
+ if (*fp != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcasecmp(value[1].data, (u_char *) "on") == 0) {
+ *fp = 1;
+
+ } else if (ngx_strcasecmp(value[1].data, (u_char *) "off") == 0) {
+ *fp = 0;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\" in \"%s\" directive, "
+ "it must be \"on\" or \"off\"",
+ value[1].data, cmd->name.data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, fp);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *field, *value;
+ ngx_conf_post_t *post;
+
+ field = (ngx_str_t *) (p + cmd->offset);
+
+ if (field->data) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *field = value[1];
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, field);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value, *s;
+ ngx_array_t **a;
+ ngx_conf_post_t *post;
+
+ a = (ngx_array_t **) (p + cmd->offset);
+
+ if (*a == NGX_CONF_UNSET_PTR) {
+ *a = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t));
+ if (*a == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ s = ngx_array_push(*a);
+ if (s == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ *s = value[1];
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, s);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value;
+ ngx_array_t **a;
+ ngx_keyval_t *kv;
+ ngx_conf_post_t *post;
+
+ a = (ngx_array_t **) (p + cmd->offset);
+
+ if (*a == NULL) {
+ *a = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t));
+ if (*a == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ kv = ngx_array_push(*a);
+ if (kv == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ kv->key = value[1];
+ kv->value = value[2];
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, kv);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_int_t *np;
+ ngx_str_t *value;
+ ngx_conf_post_t *post;
+
+
+ np = (ngx_int_t *) (p + cmd->offset);
+
+ if (*np != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+ *np = ngx_atoi(value[1].data, value[1].len);
+ if (*np == NGX_ERROR) {
+ return "invalid number";
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, np);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ size_t *sp;
+ ngx_str_t *value;
+ ngx_conf_post_t *post;
+
+
+ sp = (size_t *) (p + cmd->offset);
+ if (*sp != NGX_CONF_UNSET_SIZE) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *sp = ngx_parse_size(&value[1]);
+ if (*sp == (size_t) NGX_ERROR) {
+ return "invalid value";
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, sp);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ off_t *op;
+ ngx_str_t *value;
+ ngx_conf_post_t *post;
+
+
+ op = (off_t *) (p + cmd->offset);
+ if (*op != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *op = ngx_parse_offset(&value[1]);
+ if (*op == (off_t) NGX_ERROR) {
+ return "invalid value";
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, op);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_msec_t *msp;
+ ngx_str_t *value;
+ ngx_conf_post_t *post;
+
+
+ msp = (ngx_msec_t *) (p + cmd->offset);
+ if (*msp != NGX_CONF_UNSET_MSEC) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *msp = ngx_parse_time(&value[1], 0);
+ if (*msp == (ngx_msec_t) NGX_ERROR) {
+ return "invalid value";
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, msp);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ time_t *sp;
+ ngx_str_t *value;
+ ngx_conf_post_t *post;
+
+
+ sp = (time_t *) (p + cmd->offset);
+ if (*sp != NGX_CONF_UNSET) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *sp = ngx_parse_time(&value[1], 1);
+ if (*sp == (time_t) NGX_ERROR) {
+ return "invalid value";
+ }
+
+ if (cmd->post) {
+ post = cmd->post;
+ return post->post_handler(cf, post, sp);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_str_t *value;
+ ngx_bufs_t *bufs;
+
+
+ bufs = (ngx_bufs_t *) (p + cmd->offset);
+ if (bufs->num) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ bufs->num = ngx_atoi(value[1].data, value[1].len);
+ if (bufs->num == NGX_ERROR || bufs->num == 0) {
+ return "invalid value";
+ }
+
+ bufs->size = ngx_parse_size(&value[2]);
+ if (bufs->size == (size_t) NGX_ERROR || bufs->size == 0) {
+ return "invalid value";
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_uint_t *np, i;
+ ngx_str_t *value;
+ ngx_conf_enum_t *e;
+
+ np = (ngx_uint_t *) (p + cmd->offset);
+
+ if (*np != NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+ e = cmd->post;
+
+ for (i = 0; e[i].name.len != 0; i++) {
+ if (e[i].name.len != value[1].len
+ || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
+ {
+ continue;
+ }
+
+ *np = e[i].value;
+
+ return NGX_CONF_OK;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[1].data);
+
+ return NGX_CONF_ERROR;
+}
+
+
+char *
+ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_uint_t *np, i, m;
+ ngx_str_t *value;
+ ngx_conf_bitmask_t *mask;
+
+
+ np = (ngx_uint_t *) (p + cmd->offset);
+ value = cf->args->elts;
+ mask = cmd->post;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+ for (m = 0; mask[m].name.len != 0; m++) {
+
+ if (mask[m].name.len != value[i].len
+ || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
+ {
+ continue;
+ }
+
+ if (*np & mask[m].mask) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "duplicate value \"%s\"", value[i].data);
+
+ } else {
+ *np |= mask[m].mask;
+ }
+
+ break;
+ }
+
+ if (mask[m].name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[i].data);
+
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+#if 0
+
+char *
+ngx_conf_unsupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ return "unsupported on this platform";
+}
+
+#endif
+
+
+char *
+ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data)
+{
+ ngx_conf_deprecated_t *d = post;
+
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "the \"%s\" directive is deprecated, "
+ "use the \"%s\" directive instead",
+ d->old_name, d->new_name);
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data)
+{
+ ngx_conf_num_bounds_t *bounds = post;
+ ngx_int_t *np = data;
+
+ if (bounds->high == -1) {
+ if (*np >= bounds->low) {
+ return NGX_CONF_OK;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "value must be equal to or greater than %i",
+ bounds->low);
+
+ return NGX_CONF_ERROR;
+ }
+
+ if (*np >= bounds->low && *np <= bounds->high) {
+ return NGX_CONF_OK;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "value must be between %i and %i",
+ bounds->low, bounds->high);
+
+ return NGX_CONF_ERROR;
+}
diff --git a/app/nginx/src/core/ngx_conf_file.h b/app/nginx/src/core/ngx_conf_file.h
new file mode 100644
index 0000000..213611f
--- /dev/null
+++ b/app/nginx/src/core/ngx_conf_file.h
@@ -0,0 +1,295 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CONF_FILE_H_INCLUDED_
+#define _NGX_CONF_FILE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * AAAA number of arguments
+ * FF command flags
+ * TT command type, i.e. HTTP "location" or "server" command
+ */
+
+#define NGX_CONF_NOARGS 0x00000001
+#define NGX_CONF_TAKE1 0x00000002
+#define NGX_CONF_TAKE2 0x00000004
+#define NGX_CONF_TAKE3 0x00000008
+#define NGX_CONF_TAKE4 0x00000010
+#define NGX_CONF_TAKE5 0x00000020
+#define NGX_CONF_TAKE6 0x00000040
+#define NGX_CONF_TAKE7 0x00000080
+
+#define NGX_CONF_MAX_ARGS 8
+
+#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
+#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
+
+#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
+
+#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
+#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
+ |NGX_CONF_TAKE4)
+
+#define NGX_CONF_ARGS_NUMBER 0x000000ff
+#define NGX_CONF_BLOCK 0x00000100
+#define NGX_CONF_FLAG 0x00000200
+#define NGX_CONF_ANY 0x00000400
+#define NGX_CONF_1MORE 0x00000800
+#define NGX_CONF_2MORE 0x00001000
+
+#define NGX_DIRECT_CONF 0x00010000
+
+#define NGX_MAIN_CONF 0x01000000
+#define NGX_ANY_CONF 0x1F000000
+
+
+
+#define NGX_CONF_UNSET -1
+#define NGX_CONF_UNSET_UINT (ngx_uint_t) -1
+#define NGX_CONF_UNSET_PTR (void *) -1
+#define NGX_CONF_UNSET_SIZE (size_t) -1
+#define NGX_CONF_UNSET_MSEC (ngx_msec_t) -1
+
+
+#define NGX_CONF_OK NULL
+#define NGX_CONF_ERROR (void *) -1
+
+#define NGX_CONF_BLOCK_START 1
+#define NGX_CONF_BLOCK_DONE 2
+#define NGX_CONF_FILE_DONE 3
+
+#define NGX_CORE_MODULE 0x45524F43 /* "CORE" */
+#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */
+
+
+#define NGX_MAX_CONF_ERRSTR 1024
+
+
+struct ngx_command_s {
+ ngx_str_t name;
+ ngx_uint_t type;
+ char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+ ngx_uint_t conf;
+ ngx_uint_t offset;
+ void *post;
+};
+
+#define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }
+
+
+struct ngx_open_file_s {
+ ngx_fd_t fd;
+ ngx_str_t name;
+
+ void (*flush)(ngx_open_file_t *file, ngx_log_t *log);
+ void *data;
+};
+
+
+typedef struct {
+ ngx_file_t file;
+ ngx_buf_t *buffer;
+ ngx_buf_t *dump;
+ ngx_uint_t line;
+} ngx_conf_file_t;
+
+
+typedef struct {
+ ngx_str_t name;
+ ngx_buf_t *buffer;
+} ngx_conf_dump_t;
+
+
+typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf,
+ ngx_command_t *dummy, void *conf);
+
+
+struct ngx_conf_s {
+ char *name;
+ ngx_array_t *args;
+
+ ngx_cycle_t *cycle;
+ ngx_pool_t *pool;
+ ngx_pool_t *temp_pool;
+ ngx_conf_file_t *conf_file;
+ ngx_log_t *log;
+
+ void *ctx;
+ ngx_uint_t module_type;
+ ngx_uint_t cmd_type;
+
+ ngx_conf_handler_pt handler;
+ char *handler_conf;
+};
+
+
+typedef char *(*ngx_conf_post_handler_pt) (ngx_conf_t *cf,
+ void *data, void *conf);
+
+typedef struct {
+ ngx_conf_post_handler_pt post_handler;
+} ngx_conf_post_t;
+
+
+typedef struct {
+ ngx_conf_post_handler_pt post_handler;
+ char *old_name;
+ char *new_name;
+} ngx_conf_deprecated_t;
+
+
+typedef struct {
+ ngx_conf_post_handler_pt post_handler;
+ ngx_int_t low;
+ ngx_int_t high;
+} ngx_conf_num_bounds_t;
+
+
+typedef struct {
+ ngx_str_t name;
+ ngx_uint_t value;
+} ngx_conf_enum_t;
+
+
+#define NGX_CONF_BITMASK_SET 1
+
+typedef struct {
+ ngx_str_t name;
+ ngx_uint_t mask;
+} ngx_conf_bitmask_t;
+
+
+
+char * ngx_conf_deprecated(ngx_conf_t *cf, void *post, void *data);
+char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data);
+
+
+#define ngx_get_conf(conf_ctx, module) conf_ctx[module.index]
+
+
+
+#define ngx_conf_init_value(conf, default) \
+ if (conf == NGX_CONF_UNSET) { \
+ conf = default; \
+ }
+
+#define ngx_conf_init_ptr_value(conf, default) \
+ if (conf == NGX_CONF_UNSET_PTR) { \
+ conf = default; \
+ }
+
+#define ngx_conf_init_uint_value(conf, default) \
+ if (conf == NGX_CONF_UNSET_UINT) { \
+ conf = default; \
+ }
+
+#define ngx_conf_init_size_value(conf, default) \
+ if (conf == NGX_CONF_UNSET_SIZE) { \
+ conf = default; \
+ }
+
+#define ngx_conf_init_msec_value(conf, default) \
+ if (conf == NGX_CONF_UNSET_MSEC) { \
+ conf = default; \
+ }
+
+#define ngx_conf_merge_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET) { \
+ conf = (prev == NGX_CONF_UNSET) ? default : prev; \
+ }
+
+#define ngx_conf_merge_ptr_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET_PTR) { \
+ conf = (prev == NGX_CONF_UNSET_PTR) ? default : prev; \
+ }
+
+#define ngx_conf_merge_uint_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET_UINT) { \
+ conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev; \
+ }
+
+#define ngx_conf_merge_msec_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET_MSEC) { \
+ conf = (prev == NGX_CONF_UNSET_MSEC) ? default : prev; \
+ }
+
+#define ngx_conf_merge_sec_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET) { \
+ conf = (prev == NGX_CONF_UNSET) ? default : prev; \
+ }
+
+#define ngx_conf_merge_size_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET_SIZE) { \
+ conf = (prev == NGX_CONF_UNSET_SIZE) ? default : prev; \
+ }
+
+#define ngx_conf_merge_off_value(conf, prev, default) \
+ if (conf == NGX_CONF_UNSET) { \
+ conf = (prev == NGX_CONF_UNSET) ? default : prev; \
+ }
+
+#define ngx_conf_merge_str_value(conf, prev, default) \
+ if (conf.data == NULL) { \
+ if (prev.data) { \
+ conf.len = prev.len; \
+ conf.data = prev.data; \
+ } else { \
+ conf.len = sizeof(default) - 1; \
+ conf.data = (u_char *) default; \
+ } \
+ }
+
+#define ngx_conf_merge_bufs_value(conf, prev, default_num, default_size) \
+ if (conf.num == 0) { \
+ if (prev.num) { \
+ conf.num = prev.num; \
+ conf.size = prev.size; \
+ } else { \
+ conf.num = default_num; \
+ conf.size = default_size; \
+ } \
+ }
+
+#define ngx_conf_merge_bitmask_value(conf, prev, default) \
+ if (conf == 0) { \
+ conf = (prev == 0) ? default : prev; \
+ }
+
+
+char *ngx_conf_param(ngx_conf_t *cf);
+char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename);
+char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+
+ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name,
+ ngx_uint_t conf_prefix);
+ngx_open_file_t *ngx_conf_open_file(ngx_cycle_t *cycle, ngx_str_t *name);
+void ngx_cdecl ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf,
+ ngx_err_t err, const char *fmt, ...);
+
+
+char *ngx_conf_set_flag_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_str_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_str_array_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+char *ngx_conf_set_keyval_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_num_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_off_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+
+#endif /* _NGX_CONF_FILE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_config.h b/app/nginx/src/core/ngx_config.h
new file mode 100644
index 0000000..1861be6
--- /dev/null
+++ b/app/nginx/src/core/ngx_config.h
@@ -0,0 +1,145 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CONFIG_H_INCLUDED_
+#define _NGX_CONFIG_H_INCLUDED_
+
+
+#include <ngx_auto_headers.h>
+
+
+#if defined __DragonFly__ && !defined __FreeBSD__
+#define __FreeBSD__ 4
+#define __FreeBSD_version 480101
+#endif
+
+
+#if (NGX_FREEBSD)
+#include <ngx_freebsd_config.h>
+
+
+#elif (NGX_LINUX)
+#include <ngx_linux_config.h>
+
+
+#elif (NGX_SOLARIS)
+#include <ngx_solaris_config.h>
+
+
+#elif (NGX_DARWIN)
+#include <ngx_darwin_config.h>
+
+
+#elif (NGX_WIN32)
+#include <ngx_win32_config.h>
+
+
+#else /* POSIX */
+#include <ngx_posix_config.h>
+
+#endif
+
+
+#ifndef NGX_HAVE_SO_SNDLOWAT
+#define NGX_HAVE_SO_SNDLOWAT 1
+#endif
+
+
+#if !(NGX_WIN32)
+
+#define ngx_signal_helper(n) SIG##n
+#define ngx_signal_value(n) ngx_signal_helper(n)
+
+#define ngx_random random
+
+/* TODO: #ifndef */
+#define NGX_SHUTDOWN_SIGNAL QUIT
+#define NGX_TERMINATE_SIGNAL TERM
+#define NGX_NOACCEPT_SIGNAL WINCH
+#define NGX_RECONFIGURE_SIGNAL HUP
+
+#if (NGX_LINUXTHREADS)
+#define NGX_REOPEN_SIGNAL INFO
+#define NGX_CHANGEBIN_SIGNAL XCPU
+#else
+#define NGX_REOPEN_SIGNAL USR1
+#define NGX_CHANGEBIN_SIGNAL USR2
+#endif
+
+#define ngx_cdecl
+#define ngx_libc_cdecl
+
+#endif
+
+typedef intptr_t ngx_int_t;
+typedef uintptr_t ngx_uint_t;
+typedef intptr_t ngx_flag_t;
+
+
+#define NGX_INT32_LEN (sizeof("-2147483648") - 1)
+#define NGX_INT64_LEN (sizeof("-9223372036854775808") - 1)
+
+#if (NGX_PTR_SIZE == 4)
+#define NGX_INT_T_LEN NGX_INT32_LEN
+#define NGX_MAX_INT_T_VALUE 2147483647
+
+#else
+#define NGX_INT_T_LEN NGX_INT64_LEN
+#define NGX_MAX_INT_T_VALUE 9223372036854775807
+#endif
+
+
+#ifndef NGX_ALIGNMENT
+#define NGX_ALIGNMENT sizeof(unsigned long) /* platform word */
+#endif
+
+#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
+#define ngx_align_ptr(p, a) \
+ (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
+
+
+#define ngx_abort abort
+
+
+/* TODO: platform specific: array[NGX_INVALID_ARRAY_INDEX] must cause SIGSEGV */
+#define NGX_INVALID_ARRAY_INDEX 0x80000000
+
+
+/* TODO: auto_conf: ngx_inline inline __inline __inline__ */
+#ifndef ngx_inline
+#define ngx_inline inline
+#endif
+
+#ifndef INADDR_NONE /* Solaris */
+#define INADDR_NONE ((unsigned int) -1)
+#endif
+
+#ifdef MAXHOSTNAMELEN
+#define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN
+#else
+#define NGX_MAXHOSTNAMELEN 256
+#endif
+
+
+#define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff
+#define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff
+
+
+#if (NGX_COMPAT)
+
+#define NGX_COMPAT_BEGIN(slots) uint64_t spare[slots];
+#define NGX_COMPAT_END
+
+#else
+
+#define NGX_COMPAT_BEGIN(slots)
+#define NGX_COMPAT_END
+
+#endif
+
+
+#endif /* _NGX_CONFIG_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_connection.c b/app/nginx/src/core/ngx_connection.c
new file mode 100644
index 0000000..2af2876
--- /dev/null
+++ b/app/nginx/src/core/ngx_connection.c
@@ -0,0 +1,1404 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+ngx_os_io_t ngx_io;
+
+
+static void ngx_drain_connections(ngx_cycle_t *cycle);
+
+
+ngx_listening_t *
+ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
+ socklen_t socklen)
+{
+ size_t len;
+ ngx_listening_t *ls;
+ struct sockaddr *sa;
+ u_char text[NGX_SOCKADDR_STRLEN];
+
+ ls = ngx_array_push(&cf->cycle->listening);
+ if (ls == NULL) {
+ return NULL;
+ }
+
+ ngx_memzero(ls, sizeof(ngx_listening_t));
+
+ sa = ngx_palloc(cf->pool, socklen);
+ if (sa == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(sa, sockaddr, socklen);
+
+ ls->sockaddr = sa;
+ ls->socklen = socklen;
+
+ len = ngx_sock_ntop(sa, socklen, text, NGX_SOCKADDR_STRLEN, 1);
+ ls->addr_text.len = len;
+
+ switch (ls->sockaddr->sa_family) {
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN;
+ break;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ ls->addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+ len++;
+ break;
+#endif
+ case AF_INET:
+ ls->addr_text_max_len = NGX_INET_ADDRSTRLEN;
+ break;
+ default:
+ ls->addr_text_max_len = NGX_SOCKADDR_STRLEN;
+ break;
+ }
+
+ ls->addr_text.data = ngx_pnalloc(cf->pool, len);
+ if (ls->addr_text.data == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(ls->addr_text.data, text, len);
+
+ ls->fd = (ngx_socket_t) -1;
+ ls->type = SOCK_STREAM;
+
+ ls->backlog = NGX_LISTEN_BACKLOG;
+ ls->rcvbuf = -1;
+ ls->sndbuf = -1;
+
+#if (NGX_HAVE_SETFIB)
+ ls->setfib = -1;
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+ ls->fastopen = -1;
+#endif
+
+ return ls;
+}
+
+
+ngx_int_t
+ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls)
+{
+#if (NGX_HAVE_REUSEPORT)
+
+ ngx_int_t n;
+ ngx_core_conf_t *ccf;
+ ngx_listening_t ols;
+
+ if (!ls->reuseport) {
+ return NGX_OK;
+ }
+
+ ols = *ls;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
+ ngx_core_module);
+
+ for (n = 1; n < ccf->worker_processes; n++) {
+
+ /* create a socket for each worker process */
+
+ ls = ngx_array_push(&cf->cycle->listening);
+ if (ls == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ls = ols;
+ ls->worker = n;
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_set_inherited_sockets(ngx_cycle_t *cycle)
+{
+ size_t len;
+ ngx_uint_t i;
+ ngx_listening_t *ls;
+ socklen_t olen;
+#if (NGX_HAVE_DEFERRED_ACCEPT || NGX_HAVE_TCP_FASTOPEN)
+ ngx_err_t err;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ struct accept_filter_arg af;
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ int timeout;
+#endif
+#if (NGX_HAVE_REUSEPORT)
+ int reuseport;
+#endif
+
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+
+ ls[i].sockaddr = ngx_palloc(cycle->pool, sizeof(ngx_sockaddr_t));
+ if (ls[i].sockaddr == NULL) {
+ return NGX_ERROR;
+ }
+
+ ls[i].socklen = sizeof(ngx_sockaddr_t);
+ if (getsockname(ls[i].fd, ls[i].sockaddr, &ls[i].socklen) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+ "getsockname() of the inherited "
+ "socket #%d failed", ls[i].fd);
+ ls[i].ignore = 1;
+ continue;
+ }
+
+ switch (ls[i].sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN;
+ len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ ls[i].addr_text_max_len = NGX_UNIX_ADDRSTRLEN;
+ len = NGX_UNIX_ADDRSTRLEN;
+ break;
+#endif
+
+ case AF_INET:
+ ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN;
+ len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+ break;
+
+ default:
+ ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+ "the inherited socket #%d has "
+ "an unsupported protocol family", ls[i].fd);
+ ls[i].ignore = 1;
+ continue;
+ }
+
+ ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len);
+ if (ls[i].addr_text.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ len = ngx_sock_ntop(ls[i].sockaddr, ls[i].socklen,
+ ls[i].addr_text.data, len, 1);
+ if (len == 0) {
+ return NGX_ERROR;
+ }
+
+ ls[i].addr_text.len = len;
+
+ ls[i].backlog = NGX_LISTEN_BACKLOG;
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_TYPE, (void *) &ls[i].type,
+ &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_TYPE) %V failed", &ls[i].addr_text);
+ ls[i].ignore = 1;
+ continue;
+ }
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF, (void *) &ls[i].rcvbuf,
+ &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_RCVBUF) %V failed, ignored",
+ &ls[i].addr_text);
+
+ ls[i].rcvbuf = -1;
+ }
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF, (void *) &ls[i].sndbuf,
+ &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_SNDBUF) %V failed, ignored",
+ &ls[i].addr_text);
+
+ ls[i].sndbuf = -1;
+ }
+
+#if 0
+ /* SO_SETFIB is currently a set only option */
+
+#if (NGX_HAVE_SETFIB)
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
+ (void *) &ls[i].setfib, &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_SETFIB) %V failed, ignored",
+ &ls[i].addr_text);
+
+ ls[i].setfib = -1;
+ }
+
+#endif
+#endif
+
+#if (NGX_HAVE_REUSEPORT)
+
+ reuseport = 0;
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
+ (void *) &reuseport, &olen)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "getsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+
+ } else {
+ ls[i].reuseport = reuseport ? 1 : 0;
+ }
+
+#endif
+
+ if (ls[i].type != SOCK_STREAM) {
+ continue;
+ }
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
+ (void *) &ls[i].fastopen, &olen)
+ == -1)
+ {
+ err = ngx_socket_errno;
+
+ if (err != NGX_EOPNOTSUPP && err != NGX_ENOPROTOOPT) {
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
+ "getsockopt(TCP_FASTOPEN) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+
+ ls[i].fastopen = -1;
+ }
+
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+
+ ngx_memzero(&af, sizeof(struct accept_filter_arg));
+ olen = sizeof(struct accept_filter_arg);
+
+ if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &olen)
+ == -1)
+ {
+ err = ngx_socket_errno;
+
+ if (err == NGX_EINVAL) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
+ "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored",
+ &ls[i].addr_text);
+ continue;
+ }
+
+ if (olen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') {
+ continue;
+ }
+
+ ls[i].accept_filter = ngx_palloc(cycle->pool, 16);
+ if (ls[i].accept_filter == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn((u_char *) ls[i].accept_filter,
+ (u_char *) af.af_name, 16);
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+
+ timeout = 0;
+ olen = sizeof(int);
+
+ if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &olen)
+ == -1)
+ {
+ err = ngx_socket_errno;
+
+ if (err == NGX_EOPNOTSUPP) {
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, err,
+ "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored",
+ &ls[i].addr_text);
+ continue;
+ }
+
+ if (olen < sizeof(int) || timeout == 0) {
+ continue;
+ }
+
+ ls[i].deferred_accept = 1;
+#endif
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_open_listening_sockets(ngx_cycle_t *cycle)
+{
+ int reuseaddr;
+ ngx_uint_t i, tries, failed;
+ ngx_err_t err;
+ ngx_log_t *log;
+ ngx_socket_t s;
+ ngx_listening_t *ls;
+
+ reuseaddr = 1;
+#if (NGX_SUPPRESS_WARN)
+ failed = 0;
+#endif
+
+ log = cycle->log;
+
+ /* TODO: configurable try number */
+
+ for (tries = 5; tries; tries--) {
+ failed = 0;
+
+ /* for each listening socket */
+
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+
+ if (ls[i].ignore) {
+ continue;
+ }
+
+#if (NGX_HAVE_REUSEPORT)
+
+ if (ls[i].add_reuseport) {
+
+ /*
+ * to allow transition from a socket without SO_REUSEPORT
+ * to multiple sockets with SO_REUSEPORT, we have to set
+ * SO_REUSEPORT on the old socket before opening new ones
+ */
+
+ int reuseport = 1;
+
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_REUSEPORT,
+ (const void *) &reuseport, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+
+ ls[i].add_reuseport = 0;
+ }
+#endif
+
+ if (ls[i].fd != (ngx_socket_t) -1) {
+ continue;
+ }
+
+ if (ls[i].inherited) {
+
+ /* TODO: close on exit */
+ /* TODO: nonblocking */
+ /* TODO: deferred accept */
+
+ continue;
+ }
+
+ s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0);
+
+ if (s == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_socket_n " %V failed", &ls[i].addr_text);
+ return NGX_ERROR;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (const void *) &reuseaddr, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ "setsockopt(SO_REUSEADDR) %V failed",
+ &ls[i].addr_text);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ return NGX_ERROR;
+ }
+
+#if (NGX_HAVE_REUSEPORT)
+
+ if (ls[i].reuseport) {
+ int reuseport;
+
+ reuseport = 1;
+
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT,
+ (const void *) &reuseport, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ "setsockopt(SO_REUSEPORT) %V failed, ignored",
+ &ls[i].addr_text);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ return NGX_ERROR;
+ }
+ }
+#endif
+
+#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
+
+ if (ls[i].sockaddr->sa_family == AF_INET6) {
+ int ipv6only;
+
+ ipv6only = ls[i].ipv6only;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
+ (const void *) &ipv6only, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ "setsockopt(IPV6_V6ONLY) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+ }
+#endif
+ /* TODO: close on exit */
+
+ if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {
+ if (ngx_nonblocking(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_nonblocking_n " %V failed",
+ &ls[i].addr_text);
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ return NGX_ERROR;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0,
+ "bind() %V #%d ", &ls[i].addr_text, s);
+
+ if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
+ err = ngx_socket_errno;
+
+ if (err != NGX_EADDRINUSE || !ngx_test_config) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "bind() to %V failed", &ls[i].addr_text);
+ }
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ if (err != NGX_EADDRINUSE) {
+ return NGX_ERROR;
+ }
+
+ if (!ngx_test_config) {
+ failed = 1;
+ }
+
+ continue;
+ }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (ls[i].sockaddr->sa_family == AF_UNIX) {
+ mode_t mode;
+ u_char *name;
+
+ name = ls[i].addr_text.data + sizeof("unix:") - 1;
+ mode = (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+
+ if (chmod((char *) name, mode) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "chmod() \"%s\" failed", name);
+ }
+
+ if (ngx_test_config) {
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_delete_file_n " %s failed", name);
+ }
+ }
+ }
+#endif
+
+ if (ls[i].type != SOCK_STREAM) {
+ ls[i].fd = s;
+ continue;
+ }
+
+ if (listen(s, ls[i].backlog) == -1) {
+ err = ngx_socket_errno;
+
+ /*
+ * on OpenVZ after suspend/resume EADDRINUSE
+ * may be returned by listen() instead of bind(), see
+ * https://bugzilla.openvz.org/show_bug.cgi?id=2470
+ */
+
+ if (err != NGX_EADDRINUSE || !ngx_test_config) {
+ ngx_log_error(NGX_LOG_EMERG, log, err,
+ "listen() to %V, backlog %d failed",
+ &ls[i].addr_text, ls[i].backlog);
+ }
+
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+
+ if (err != NGX_EADDRINUSE) {
+ return NGX_ERROR;
+ }
+
+ if (!ngx_test_config) {
+ failed = 1;
+ }
+
+ continue;
+ }
+
+ ls[i].listen = 1;
+
+ ls[i].fd = s;
+ }
+
+ if (!failed) {
+ break;
+ }
+
+ /* TODO: delay configurable */
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "try again to bind() after 500ms");
+
+ ngx_msleep(500);
+ }
+
+ if (failed) {
+ ngx_log_error(NGX_LOG_EMERG, log, 0, "still could not bind()");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+void
+ngx_configure_listening_sockets(ngx_cycle_t *cycle)
+{
+ int value;
+ ngx_uint_t i;
+ ngx_listening_t *ls;
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ struct accept_filter_arg af;
+#endif
+
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+
+ ls[i].log = *ls[i].logp;
+
+ if (ls[i].rcvbuf != -1) {
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_RCVBUF,
+ (const void *) &ls[i].rcvbuf, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_RCVBUF, %d) %V failed, ignored",
+ ls[i].rcvbuf, &ls[i].addr_text);
+ }
+ }
+
+ if (ls[i].sndbuf != -1) {
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SNDBUF,
+ (const void *) &ls[i].sndbuf, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_SNDBUF, %d) %V failed, ignored",
+ ls[i].sndbuf, &ls[i].addr_text);
+ }
+ }
+
+ if (ls[i].keepalive) {
+ value = (ls[i].keepalive == 1) ? 1 : 0;
+
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_KEEPALIVE,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_KEEPALIVE, %d) %V failed, ignored",
+ value, &ls[i].addr_text);
+ }
+ }
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+
+ if (ls[i].keepidle) {
+ value = ls[i].keepidle;
+
+#if (NGX_KEEPALIVE_FACTOR)
+ value *= NGX_KEEPALIVE_FACTOR;
+#endif
+
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_KEEPIDLE, %d) %V failed, ignored",
+ value, &ls[i].addr_text);
+ }
+ }
+
+ if (ls[i].keepintvl) {
+ value = ls[i].keepintvl;
+
+#if (NGX_KEEPALIVE_FACTOR)
+ value *= NGX_KEEPALIVE_FACTOR;
+#endif
+
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPINTVL,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_KEEPINTVL, %d) %V failed, ignored",
+ value, &ls[i].addr_text);
+ }
+ }
+
+ if (ls[i].keepcnt) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_KEEPCNT,
+ (const void *) &ls[i].keepcnt, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_KEEPCNT, %d) %V failed, ignored",
+ ls[i].keepcnt, &ls[i].addr_text);
+ }
+ }
+
+#endif
+
+#if (NGX_HAVE_SETFIB)
+ if (ls[i].setfib != -1) {
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_SETFIB,
+ (const void *) &ls[i].setfib, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_SETFIB, %d) %V failed, ignored",
+ ls[i].setfib, &ls[i].addr_text);
+ }
+ }
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+ if (ls[i].fastopen != -1) {
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_FASTOPEN,
+ (const void *) &ls[i].fastopen, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_FASTOPEN, %d) %V failed, ignored",
+ ls[i].fastopen, &ls[i].addr_text);
+ }
+ }
+#endif
+
+#if 0
+ if (1) {
+ int tcp_nodelay = 1;
+
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_NODELAY,
+ (const void *) &tcp_nodelay, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_NODELAY) %V failed, ignored",
+ &ls[i].addr_text);
+ }
+ }
+#endif
+
+ if (ls[i].listen) {
+
+ /* change backlog via listen() */
+
+ if (listen(ls[i].fd, ls[i].backlog) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "listen() to %V, backlog %d failed, ignored",
+ &ls[i].addr_text, ls[i].backlog);
+ }
+ }
+
+ /*
+ * setting deferred mode should be last operation on socket,
+ * because code may prematurely continue cycle on failure
+ */
+
+#if (NGX_HAVE_DEFERRED_ACCEPT)
+
+#ifdef SO_ACCEPTFILTER
+
+ if (ls[i].delete_deferred) {
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, NULL, 0)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_ACCEPTFILTER, NULL) "
+ "for %V failed, ignored",
+ &ls[i].addr_text);
+
+ if (ls[i].accept_filter) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "could not change the accept filter "
+ "to \"%s\" for %V, ignored",
+ ls[i].accept_filter, &ls[i].addr_text);
+ }
+
+ continue;
+ }
+
+ ls[i].deferred_accept = 0;
+ }
+
+ if (ls[i].add_deferred) {
+ ngx_memzero(&af, sizeof(struct accept_filter_arg));
+ (void) ngx_cpystrn((u_char *) af.af_name,
+ (u_char *) ls[i].accept_filter, 16);
+
+ if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER,
+ &af, sizeof(struct accept_filter_arg))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(SO_ACCEPTFILTER, \"%s\") "
+ "for %V failed, ignored",
+ ls[i].accept_filter, &ls[i].addr_text);
+ continue;
+ }
+
+ ls[i].deferred_accept = 1;
+ }
+
+#endif
+
+#ifdef TCP_DEFER_ACCEPT
+
+ if (ls[i].add_deferred || ls[i].delete_deferred) {
+
+ if (ls[i].add_deferred) {
+ /*
+ * There is no way to find out how long a connection was
+ * in queue (and a connection may bypass deferred queue at all
+ * if syncookies were used), hence we use 1 second timeout
+ * here.
+ */
+ value = 1;
+
+ } else {
+ value = 0;
+ }
+
+ if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT,
+ &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(TCP_DEFER_ACCEPT, %d) for %V failed, "
+ "ignored",
+ value, &ls[i].addr_text);
+
+ continue;
+ }
+ }
+
+ if (ls[i].add_deferred) {
+ ls[i].deferred_accept = 1;
+ }
+
+#endif
+
+#endif /* NGX_HAVE_DEFERRED_ACCEPT */
+
+#if (NGX_HAVE_IP_RECVDSTADDR)
+
+ if (ls[i].wildcard
+ && ls[i].type == SOCK_DGRAM
+ && ls[i].sockaddr->sa_family == AF_INET)
+ {
+ value = 1;
+
+ if (setsockopt(ls[i].fd, IPPROTO_IP, IP_RECVDSTADDR,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(IP_RECVDSTADDR) "
+ "for %V failed, ignored",
+ &ls[i].addr_text);
+ }
+ }
+
+#elif (NGX_HAVE_IP_PKTINFO)
+
+ if (ls[i].wildcard
+ && ls[i].type == SOCK_DGRAM
+ && ls[i].sockaddr->sa_family == AF_INET)
+ {
+ value = 1;
+
+ if (setsockopt(ls[i].fd, IPPROTO_IP, IP_PKTINFO,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(IP_PKTINFO) "
+ "for %V failed, ignored",
+ &ls[i].addr_text);
+ }
+ }
+
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+
+ if (ls[i].wildcard
+ && ls[i].type == SOCK_DGRAM
+ && ls[i].sockaddr->sa_family == AF_INET6)
+ {
+ value = 1;
+
+ if (setsockopt(ls[i].fd, IPPROTO_IPV6, IPV6_RECVPKTINFO,
+ (const void *) &value, sizeof(int))
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
+ "setsockopt(IPV6_RECVPKTINFO) "
+ "for %V failed, ignored",
+ &ls[i].addr_text);
+ }
+ }
+
+#endif
+ }
+
+ return;
+}
+
+
+void
+ngx_close_listening_sockets(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_listening_t *ls;
+ ngx_connection_t *c;
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+ return;
+ }
+
+ ngx_accept_mutex_held = 0;
+ ngx_use_accept_mutex = 0;
+
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+
+ c = ls[i].connection;
+
+ if (c) {
+ if (c->read->active) {
+ if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
+
+ /*
+ * it seems that Linux-2.6.x OpenVZ sends events
+ * for closed shared listening sockets unless
+ * the events was explicitly deleted
+ */
+
+ ngx_del_event(c->read, NGX_READ_EVENT, 0);
+
+ } else {
+ ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
+ }
+ }
+
+ ngx_free_connection(c);
+
+ c->fd = (ngx_socket_t) -1;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
+ "close listening %V #%d ", &ls[i].addr_text, ls[i].fd);
+
+ if (ngx_close_socket(ls[i].fd) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed", &ls[i].addr_text);
+ }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (ls[i].sockaddr->sa_family == AF_UNIX
+ && ngx_process <= NGX_PROCESS_MASTER
+ && ngx_new_binary == 0)
+ {
+ u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+ ngx_delete_file_n " %s failed", name);
+ }
+ }
+
+#endif
+
+ ls[i].fd = (ngx_socket_t) -1;
+ }
+
+ cycle->listening.nelts = 0;
+}
+
+
+ngx_connection_t *
+ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
+{
+ ngx_uint_t instance;
+ ngx_event_t *rev, *wev;
+ ngx_connection_t *c;
+
+ /* disable warning: Win32 SOCKET is u_int while UNIX socket is int */
+
+ if (ngx_cycle->files && (ngx_uint_t) s >= ngx_cycle->files_n) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "the new socket has number %d, "
+ "but only %ui files are available",
+ s, ngx_cycle->files_n);
+ return NULL;
+ }
+
+ c = ngx_cycle->free_connections;
+
+ if (c == NULL) {
+ ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
+ c = ngx_cycle->free_connections;
+ }
+
+ if (c == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "%ui worker_connections are not enough",
+ ngx_cycle->connection_n);
+
+ return NULL;
+ }
+
+ ngx_cycle->free_connections = c->data;
+ ngx_cycle->free_connection_n--;
+
+ if (ngx_cycle->files && ngx_cycle->files[s] == NULL) {
+ ngx_cycle->files[s] = c;
+ }
+
+ rev = c->read;
+ wev = c->write;
+
+ ngx_memzero(c, sizeof(ngx_connection_t));
+
+ c->read = rev;
+ c->write = wev;
+ c->fd = s;
+ c->log = log;
+
+ instance = rev->instance;
+
+ ngx_memzero(rev, sizeof(ngx_event_t));
+ ngx_memzero(wev, sizeof(ngx_event_t));
+
+ rev->instance = !instance;
+ wev->instance = !instance;
+
+ rev->index = NGX_INVALID_INDEX;
+ wev->index = NGX_INVALID_INDEX;
+
+ rev->data = c;
+ wev->data = c;
+
+ wev->write = 1;
+
+ return c;
+}
+
+
+void
+ngx_free_connection(ngx_connection_t *c)
+{
+ c->data = ngx_cycle->free_connections;
+ ngx_cycle->free_connections = c;
+ ngx_cycle->free_connection_n++;
+
+ if (ngx_cycle->files && ngx_cycle->files[c->fd] == c) {
+ ngx_cycle->files[c->fd] = NULL;
+ }
+}
+
+
+void
+ngx_close_connection(ngx_connection_t *c)
+{
+ ngx_err_t err;
+ ngx_uint_t log_error, level;
+ ngx_socket_t fd;
+
+ if (c->fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
+ return;
+ }
+
+ if (c->read->timer_set) {
+ ngx_del_timer(c->read);
+ }
+
+ if (c->write->timer_set) {
+ ngx_del_timer(c->write);
+ }
+
+ if (!c->shared) {
+ if (ngx_del_conn) {
+ ngx_del_conn(c, NGX_CLOSE_EVENT);
+
+ } else {
+ if (c->read->active || c->read->disabled) {
+ ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
+ }
+
+ if (c->write->active || c->write->disabled) {
+ ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
+ }
+ }
+ }
+
+ if (c->read->posted) {
+ ngx_delete_posted_event(c->read);
+ }
+
+ if (c->write->posted) {
+ ngx_delete_posted_event(c->write);
+ }
+
+ c->read->closed = 1;
+ c->write->closed = 1;
+
+ ngx_reusable_connection(c, 0);
+
+ log_error = c->log_error;
+
+ ngx_free_connection(c);
+
+ fd = c->fd;
+ c->fd = (ngx_socket_t) -1;
+
+ if (c->shared) {
+ return;
+ }
+
+ if (ngx_close_socket(fd) == -1) {
+
+ err = ngx_socket_errno;
+
+ if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {
+
+ switch (log_error) {
+
+ case NGX_ERROR_INFO:
+ level = NGX_LOG_INFO;
+ break;
+
+ case NGX_ERROR_ERR:
+ level = NGX_LOG_ERR;
+ break;
+
+ default:
+ level = NGX_LOG_CRIT;
+ }
+
+ } else {
+ level = NGX_LOG_CRIT;
+ }
+
+ ngx_log_error(level, c->log, err, ngx_close_socket_n " %d failed", fd);
+ }
+}
+
+
+void
+ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable)
+{
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "reusable connection: %ui", reusable);
+
+ if (c->reusable) {
+ ngx_queue_remove(&c->queue);
+ ngx_cycle->reusable_connections_n--;
+
+#if (NGX_STAT_STUB)
+ (void) ngx_atomic_fetch_add(ngx_stat_waiting, -1);
+#endif
+ }
+
+ c->reusable = reusable;
+
+ if (reusable) {
+ /* need cast as ngx_cycle is volatile */
+
+ ngx_queue_insert_head(
+ (ngx_queue_t *) &ngx_cycle->reusable_connections_queue, &c->queue);
+ ngx_cycle->reusable_connections_n++;
+
+#if (NGX_STAT_STUB)
+ (void) ngx_atomic_fetch_add(ngx_stat_waiting, 1);
+#endif
+ }
+}
+
+
+static void
+ngx_drain_connections(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i, n;
+ ngx_queue_t *q;
+ ngx_connection_t *c;
+
+ n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1);
+
+ for (i = 0; i < n; i++) {
+ if (ngx_queue_empty(&cycle->reusable_connections_queue)) {
+ break;
+ }
+
+ q = ngx_queue_last(&cycle->reusable_connections_queue);
+ c = ngx_queue_data(q, ngx_connection_t, queue);
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "reusing connection");
+
+ c->close = 1;
+ c->read->handler(c->read);
+ }
+}
+
+
+void
+ngx_close_idle_connections(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_connection_t *c;
+
+ c = cycle->connections;
+
+ for (i = 0; i < cycle->connection_n; i++) {
+
+ /* THREAD: lock */
+
+ if (c[i].fd != (ngx_socket_t) -1 && c[i].idle) {
+ c[i].close = 1;
+ c[i].read->handler(c[i].read);
+ }
+ }
+}
+
+
+ngx_int_t
+ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
+ ngx_uint_t port)
+{
+ socklen_t len;
+ ngx_uint_t addr;
+ ngx_sockaddr_t sa;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t i;
+ struct sockaddr_in6 *sin6;
+#endif
+
+ addr = 0;
+
+ if (c->local_socklen) {
+ switch (c->local_sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+
+ for (i = 0; addr == 0 && i < 16; i++) {
+ addr |= sin6->sin6_addr.s6_addr[i];
+ }
+
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ addr = 1;
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) c->local_sockaddr;
+ addr = sin->sin_addr.s_addr;
+ break;
+ }
+ }
+
+ if (addr == 0) {
+
+ len = sizeof(ngx_sockaddr_t);
+
+ if (getsockname(c->fd, &sa.sockaddr, &len) == -1) {
+ ngx_connection_error(c, ngx_socket_errno, "getsockname() failed");
+ return NGX_ERROR;
+ }
+
+ c->local_sockaddr = ngx_palloc(c->pool, len);
+ if (c->local_sockaddr == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(c->local_sockaddr, &sa, len);
+
+ c->local_socklen = len;
+ }
+
+ if (s == NULL) {
+ return NGX_OK;
+ }
+
+ s->len = ngx_sock_ntop(c->local_sockaddr, c->local_socklen,
+ s->data, s->len, port);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
+{
+ ngx_uint_t level;
+
+ /* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */
+
+ if ((err == NGX_ECONNRESET
+#if (NGX_WIN32)
+ || err == NGX_ECONNABORTED
+#endif
+ ) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET)
+ {
+ return 0;
+ }
+
+#if (NGX_SOLARIS)
+ if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) {
+ return 0;
+ }
+#endif
+
+ if (err == 0
+ || err == NGX_ECONNRESET
+#if (NGX_WIN32)
+ || err == NGX_ECONNABORTED
+#else
+ || err == NGX_EPIPE
+#endif
+ || err == NGX_ENOTCONN
+ || err == NGX_ETIMEDOUT
+ || err == NGX_ECONNREFUSED
+ || err == NGX_ENETDOWN
+ || err == NGX_ENETUNREACH
+ || err == NGX_EHOSTDOWN
+ || err == NGX_EHOSTUNREACH)
+ {
+ switch (c->log_error) {
+
+ case NGX_ERROR_IGNORE_EINVAL:
+ case NGX_ERROR_IGNORE_ECONNRESET:
+ case NGX_ERROR_INFO:
+ level = NGX_LOG_INFO;
+ break;
+
+ default:
+ level = NGX_LOG_ERR;
+ }
+
+ } else {
+ level = NGX_LOG_ALERT;
+ }
+
+ ngx_log_error(level, c->log, err, text);
+
+ return NGX_ERROR;
+}
diff --git a/app/nginx/src/core/ngx_connection.h b/app/nginx/src/core/ngx_connection.h
new file mode 100644
index 0000000..1d3e3a3
--- /dev/null
+++ b/app/nginx/src/core/ngx_connection.h
@@ -0,0 +1,224 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CONNECTION_H_INCLUDED_
+#define _NGX_CONNECTION_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct ngx_listening_s ngx_listening_t;
+
+struct ngx_listening_s {
+ ngx_socket_t fd;
+
+ struct sockaddr *sockaddr;
+ socklen_t socklen; /* size of sockaddr */
+ size_t addr_text_max_len;
+ ngx_str_t addr_text;
+
+ int type;
+
+ int backlog;
+ int rcvbuf;
+ int sndbuf;
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+ int keepidle;
+ int keepintvl;
+ int keepcnt;
+#endif
+
+ /* handler of accepted connection */
+ ngx_connection_handler_pt handler;
+
+ void *servers; /* array of ngx_http_in_addr_t, for example */
+
+ ngx_log_t log;
+ ngx_log_t *logp;
+
+ size_t pool_size;
+ /* should be here because of the AcceptEx() preread */
+ size_t post_accept_buffer_size;
+ /* should be here because of the deferred accept */
+ ngx_msec_t post_accept_timeout;
+
+ ngx_listening_t *previous;
+ ngx_connection_t *connection;
+
+ ngx_uint_t worker;
+
+ unsigned open:1;
+ unsigned remain:1;
+ unsigned ignore:1;
+
+ unsigned bound:1; /* already bound */
+ unsigned inherited:1; /* inherited from previous process */
+ unsigned nonblocking_accept:1;
+ unsigned listen:1;
+ unsigned nonblocking:1;
+ unsigned shared:1; /* shared between threads or processes */
+ unsigned addr_ntop:1;
+ unsigned wildcard:1;
+
+#if (NGX_HAVE_INET6)
+ unsigned ipv6only:1;
+#endif
+ unsigned reuseport:1;
+ unsigned add_reuseport:1;
+ unsigned keepalive:2;
+
+ unsigned deferred_accept:1;
+ unsigned delete_deferred:1;
+ unsigned add_deferred:1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ char *accept_filter;
+#endif
+#if (NGX_HAVE_SETFIB)
+ int setfib;
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+ int fastopen;
+#endif
+
+};
+
+
+typedef enum {
+ NGX_ERROR_ALERT = 0,
+ NGX_ERROR_ERR,
+ NGX_ERROR_INFO,
+ NGX_ERROR_IGNORE_ECONNRESET,
+ NGX_ERROR_IGNORE_EINVAL
+} ngx_connection_log_error_e;
+
+
+typedef enum {
+ NGX_TCP_NODELAY_UNSET = 0,
+ NGX_TCP_NODELAY_SET,
+ NGX_TCP_NODELAY_DISABLED
+} ngx_connection_tcp_nodelay_e;
+
+
+typedef enum {
+ NGX_TCP_NOPUSH_UNSET = 0,
+ NGX_TCP_NOPUSH_SET,
+ NGX_TCP_NOPUSH_DISABLED
+} ngx_connection_tcp_nopush_e;
+
+
+#define NGX_LOWLEVEL_BUFFERED 0x0f
+#define NGX_SSL_BUFFERED 0x01
+#define NGX_HTTP_V2_BUFFERED 0x02
+
+
+struct ngx_connection_s {
+ void *data;
+ ngx_event_t *read;
+ ngx_event_t *write;
+
+ ngx_socket_t fd;
+
+ ngx_recv_pt recv;
+ ngx_send_pt send;
+ ngx_recv_chain_pt recv_chain;
+ ngx_send_chain_pt send_chain;
+
+ ngx_listening_t *listening;
+
+ off_t sent;
+
+ ngx_log_t *log;
+
+ ngx_pool_t *pool;
+
+ int type;
+
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t addr_text;
+
+ ngx_str_t proxy_protocol_addr;
+ in_port_t proxy_protocol_port;
+
+#if (NGX_SSL || NGX_COMPAT)
+ ngx_ssl_connection_t *ssl;
+#endif
+
+ struct sockaddr *local_sockaddr;
+ socklen_t local_socklen;
+
+ ngx_buf_t *buffer;
+
+ ngx_queue_t queue;
+
+ ngx_atomic_uint_t number;
+
+ ngx_uint_t requests;
+
+ unsigned buffered:8;
+
+ unsigned log_error:3; /* ngx_connection_log_error_e */
+
+ unsigned timedout:1;
+ unsigned error:1;
+ unsigned destroyed:1;
+
+ unsigned idle:1;
+ unsigned reusable:1;
+ unsigned close:1;
+ unsigned shared:1;
+
+ unsigned sendfile:1;
+ unsigned sndlowat:1;
+ unsigned tcp_nodelay:2; /* ngx_connection_tcp_nodelay_e */
+ unsigned tcp_nopush:2; /* ngx_connection_tcp_nopush_e */
+
+ unsigned need_last_buf:1;
+
+#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
+ unsigned busy_count:2;
+#endif
+
+#if (NGX_THREADS || NGX_COMPAT)
+ ngx_thread_task_t *sendfile_task;
+#endif
+};
+
+
+#define ngx_set_connection_log(c, l) \
+ \
+ c->log->file = l->file; \
+ c->log->next = l->next; \
+ c->log->writer = l->writer; \
+ c->log->wdata = l->wdata; \
+ if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \
+ c->log->log_level = l->log_level; \
+ }
+
+
+ngx_listening_t *ngx_create_listening(ngx_conf_t *cf, struct sockaddr *sockaddr,
+ socklen_t socklen);
+ngx_int_t ngx_clone_listening(ngx_conf_t *cf, ngx_listening_t *ls);
+ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle);
+ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle);
+void ngx_configure_listening_sockets(ngx_cycle_t *cycle);
+void ngx_close_listening_sockets(ngx_cycle_t *cycle);
+void ngx_close_connection(ngx_connection_t *c);
+void ngx_close_idle_connections(ngx_cycle_t *cycle);
+ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s,
+ ngx_uint_t port);
+ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text);
+
+ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log);
+void ngx_free_connection(ngx_connection_t *c);
+
+void ngx_reusable_connection(ngx_connection_t *c, ngx_uint_t reusable);
+
+#endif /* _NGX_CONNECTION_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_core.h b/app/nginx/src/core/ngx_core.h
new file mode 100644
index 0000000..2069373
--- /dev/null
+++ b/app/nginx/src/core/ngx_core.h
@@ -0,0 +1,111 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CORE_H_INCLUDED_
+#define _NGX_CORE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+
+
+typedef struct ngx_module_s ngx_module_t;
+typedef struct ngx_conf_s ngx_conf_t;
+typedef struct ngx_cycle_s ngx_cycle_t;
+typedef struct ngx_pool_s ngx_pool_t;
+typedef struct ngx_chain_s ngx_chain_t;
+typedef struct ngx_log_s ngx_log_t;
+typedef struct ngx_open_file_s ngx_open_file_t;
+typedef struct ngx_command_s ngx_command_t;
+typedef struct ngx_file_s ngx_file_t;
+typedef struct ngx_event_s ngx_event_t;
+typedef struct ngx_event_aio_s ngx_event_aio_t;
+typedef struct ngx_connection_s ngx_connection_t;
+typedef struct ngx_thread_task_s ngx_thread_task_t;
+typedef struct ngx_ssl_s ngx_ssl_t;
+typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
+
+typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
+typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
+
+
+#define NGX_OK 0
+#define NGX_ERROR -1
+#define NGX_AGAIN -2
+#define NGX_BUSY -3
+#define NGX_DONE -4
+#define NGX_DECLINED -5
+#define NGX_ABORT -6
+
+
+#include <ngx_errno.h>
+#include <ngx_atomic.h>
+#include <ngx_thread.h>
+#include <ngx_rbtree.h>
+#include <ngx_time.h>
+#include <ngx_socket.h>
+#include <ngx_string.h>
+#include <ngx_files.h>
+#include <ngx_shmem.h>
+#include <ngx_process.h>
+#include <ngx_user.h>
+#include <ngx_dlopen.h>
+#include <ngx_parse.h>
+#include <ngx_parse_time.h>
+#include <ngx_log.h>
+#include <ngx_alloc.h>
+#include <ngx_palloc.h>
+#include <ngx_buf.h>
+#include <ngx_queue.h>
+#include <ngx_array.h>
+#include <ngx_list.h>
+#include <ngx_hash.h>
+#include <ngx_file.h>
+#include <ngx_crc.h>
+#include <ngx_crc32.h>
+#include <ngx_murmurhash.h>
+#if (NGX_PCRE)
+#include <ngx_regex.h>
+#endif
+#include <ngx_radix_tree.h>
+#include <ngx_times.h>
+#include <ngx_rwlock.h>
+#include <ngx_shmtx.h>
+#include <ngx_slab.h>
+#include <ngx_inet.h>
+#include <ngx_cycle.h>
+#include <ngx_resolver.h>
+#if (NGX_OPENSSL)
+#include <ngx_event_openssl.h>
+#endif
+#include <ngx_process_cycle.h>
+#include <ngx_conf_file.h>
+#include <ngx_module.h>
+#include <ngx_open_file_cache.h>
+#include <ngx_os.h>
+#include <ngx_connection.h>
+#include <ngx_syslog.h>
+#include <ngx_proxy_protocol.h>
+
+
+#define LF (u_char) '\n'
+#define CR (u_char) '\r'
+#define CRLF "\r\n"
+
+
+#define ngx_abs(value) (((value) >= 0) ? (value) : - (value))
+#define ngx_max(val1, val2) ((val1 < val2) ? (val2) : (val1))
+#define ngx_min(val1, val2) ((val1 > val2) ? (val2) : (val1))
+
+void ngx_cpuinfo(void);
+
+#if (NGX_HAVE_OPENAT)
+#define NGX_DISABLE_SYMLINKS_OFF 0
+#define NGX_DISABLE_SYMLINKS_ON 1
+#define NGX_DISABLE_SYMLINKS_NOTOWNER 2
+#endif
+
+#endif /* _NGX_CORE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_cpuinfo.c b/app/nginx/src/core/ngx_cpuinfo.c
new file mode 100644
index 0000000..7205319
--- /dev/null
+++ b/app/nginx/src/core/ngx_cpuinfo.c
@@ -0,0 +1,139 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (( __i386__ || __amd64__ ) && ( __GNUC__ || __INTEL_COMPILER ))
+
+
+static ngx_inline void ngx_cpuid(uint32_t i, uint32_t *buf);
+
+
+#if ( __i386__ )
+
+static ngx_inline void
+ngx_cpuid(uint32_t i, uint32_t *buf)
+{
+
+ /*
+ * we could not use %ebx as output parameter if gcc builds PIC,
+ * and we could not save %ebx on stack, because %esp is used,
+ * when the -fomit-frame-pointer optimization is specified.
+ */
+
+ __asm__ (
+
+ " mov %%ebx, %%esi; "
+
+ " cpuid; "
+ " mov %%eax, (%1); "
+ " mov %%ebx, 4(%1); "
+ " mov %%edx, 8(%1); "
+ " mov %%ecx, 12(%1); "
+
+ " mov %%esi, %%ebx; "
+
+ : : "a" (i), "D" (buf) : "ecx", "edx", "esi", "memory" );
+}
+
+
+#else /* __amd64__ */
+
+
+static ngx_inline void
+ngx_cpuid(uint32_t i, uint32_t *buf)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ __asm__ (
+
+ "cpuid"
+
+ : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (i) );
+
+ buf[0] = eax;
+ buf[1] = ebx;
+ buf[2] = edx;
+ buf[3] = ecx;
+}
+
+
+#endif
+
+
+/* auto detect the L2 cache line size of modern and widespread CPUs */
+
+void
+ngx_cpuinfo(void)
+{
+ u_char *vendor;
+ uint32_t vbuf[5], cpu[4], model;
+
+ vbuf[0] = 0;
+ vbuf[1] = 0;
+ vbuf[2] = 0;
+ vbuf[3] = 0;
+ vbuf[4] = 0;
+
+ ngx_cpuid(0, vbuf);
+
+ vendor = (u_char *) &vbuf[1];
+
+ if (vbuf[0] == 0) {
+ return;
+ }
+
+ ngx_cpuid(1, cpu);
+
+ if (ngx_strcmp(vendor, "GenuineIntel") == 0) {
+
+ switch ((cpu[0] & 0xf00) >> 8) {
+
+ /* Pentium */
+ case 5:
+ ngx_cacheline_size = 32;
+ break;
+
+ /* Pentium Pro, II, III */
+ case 6:
+ ngx_cacheline_size = 32;
+
+ model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0);
+
+ if (model >= 0xd0) {
+ /* Intel Core, Core 2, Atom */
+ ngx_cacheline_size = 64;
+ }
+
+ break;
+
+ /*
+ * Pentium 4, although its cache line size is 64 bytes,
+ * it prefetches up to two cache lines during memory read
+ */
+ case 15:
+ ngx_cacheline_size = 128;
+ break;
+ }
+
+ } else if (ngx_strcmp(vendor, "AuthenticAMD") == 0) {
+ ngx_cacheline_size = 64;
+ }
+}
+
+#else
+
+
+void
+ngx_cpuinfo(void)
+{
+}
+
+
+#endif
diff --git a/app/nginx/src/core/ngx_crc.h b/app/nginx/src/core/ngx_crc.h
new file mode 100644
index 0000000..35981bc
--- /dev/null
+++ b/app/nginx/src/core/ngx_crc.h
@@ -0,0 +1,39 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CRC_H_INCLUDED_
+#define _NGX_CRC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/* 32-bit crc16 */
+
+static ngx_inline uint32_t
+ngx_crc(u_char *data, size_t len)
+{
+ uint32_t sum;
+
+ for (sum = 0; len; len--) {
+
+ /*
+ * gcc 2.95.2 x86 and icc 7.1.006 compile
+ * that operator into the single "rol" opcode,
+ * msvc 6.0sp2 compiles it into four opcodes.
+ */
+ sum = sum >> 1 | sum << 31;
+
+ sum += *data++;
+ }
+
+ return sum;
+}
+
+
+#endif /* _NGX_CRC_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_crc32.c b/app/nginx/src/core/ngx_crc32.c
new file mode 100644
index 0000000..a5b4017
--- /dev/null
+++ b/app/nginx/src/core/ngx_crc32.c
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * The code and lookup tables are based on the algorithm
+ * described at http://www.w3.org/TR/PNG/
+ *
+ * The 256 element lookup table takes 1024 bytes, and it may be completely
+ * cached after processing about 30-60 bytes of data. So for short data
+ * we use the 16 element lookup table that takes only 64 bytes and align it
+ * to CPU cache line size. Of course, the small table adds code inside
+ * CRC32 loop, but the cache misses overhead is bigger than overhead of
+ * the additional code. For example, ngx_crc32_short() of 16 bytes of data
+ * takes half as much CPU clocks than ngx_crc32_long().
+ */
+
+
+static uint32_t ngx_crc32_table16[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+};
+
+
+uint32_t ngx_crc32_table256[] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+
+uint32_t *ngx_crc32_table_short = ngx_crc32_table16;
+
+
+ngx_int_t
+ngx_crc32_table_init(void)
+{
+ void *p;
+
+ if (((uintptr_t) ngx_crc32_table_short
+ & ~((uintptr_t) ngx_cacheline_size - 1))
+ == (uintptr_t) ngx_crc32_table_short)
+ {
+ return NGX_OK;
+ }
+
+ p = ngx_alloc(16 * sizeof(uint32_t) + ngx_cacheline_size, ngx_cycle->log);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_align_ptr(p, ngx_cacheline_size);
+
+ ngx_memcpy(p, ngx_crc32_table16, 16 * sizeof(uint32_t));
+
+ ngx_crc32_table_short = p;
+
+ return NGX_OK;
+}
diff --git a/app/nginx/src/core/ngx_crc32.h b/app/nginx/src/core/ngx_crc32.h
new file mode 100644
index 0000000..f6d6865
--- /dev/null
+++ b/app/nginx/src/core/ngx_crc32.h
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CRC32_H_INCLUDED_
+#define _NGX_CRC32_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+extern uint32_t *ngx_crc32_table_short;
+extern uint32_t ngx_crc32_table256[];
+
+
+static ngx_inline uint32_t
+ngx_crc32_short(u_char *p, size_t len)
+{
+ u_char c;
+ uint32_t crc;
+
+ crc = 0xffffffff;
+
+ while (len--) {
+ c = *p++;
+ crc = ngx_crc32_table_short[(crc ^ (c & 0xf)) & 0xf] ^ (crc >> 4);
+ crc = ngx_crc32_table_short[(crc ^ (c >> 4)) & 0xf] ^ (crc >> 4);
+ }
+
+ return crc ^ 0xffffffff;
+}
+
+
+static ngx_inline uint32_t
+ngx_crc32_long(u_char *p, size_t len)
+{
+ uint32_t crc;
+
+ crc = 0xffffffff;
+
+ while (len--) {
+ crc = ngx_crc32_table256[(crc ^ *p++) & 0xff] ^ (crc >> 8);
+ }
+
+ return crc ^ 0xffffffff;
+}
+
+
+#define ngx_crc32_init(crc) \
+ crc = 0xffffffff
+
+
+static ngx_inline void
+ngx_crc32_update(uint32_t *crc, u_char *p, size_t len)
+{
+ uint32_t c;
+
+ c = *crc;
+
+ while (len--) {
+ c = ngx_crc32_table256[(c ^ *p++) & 0xff] ^ (c >> 8);
+ }
+
+ *crc = c;
+}
+
+
+#define ngx_crc32_final(crc) \
+ crc ^= 0xffffffff
+
+
+ngx_int_t ngx_crc32_table_init(void);
+
+
+#endif /* _NGX_CRC32_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_crypt.c b/app/nginx/src/core/ngx_crypt.c
new file mode 100644
index 0000000..868dc5d
--- /dev/null
+++ b/app/nginx/src/core/ngx_crypt.c
@@ -0,0 +1,270 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_crypt.h>
+#include <ngx_md5.h>
+#include <ngx_sha1.h>
+
+
+#if (NGX_CRYPT)
+
+static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+
+
+static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n);
+
+
+ngx_int_t
+ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) {
+ return ngx_crypt_apr1(pool, key, salt, encrypted);
+
+ } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) {
+ return ngx_crypt_plain(pool, key, salt, encrypted);
+
+ } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) {
+ return ngx_crypt_ssha(pool, key, salt, encrypted);
+
+ } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) {
+ return ngx_crypt_sha(pool, key, salt, encrypted);
+ }
+
+ /* fallback to libc crypt() */
+
+ return ngx_libc_crypt(pool, key, salt, encrypted);
+}
+
+
+static ngx_int_t
+ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ ngx_int_t n;
+ ngx_uint_t i;
+ u_char *p, *last, final[16];
+ size_t saltlen, keylen;
+ ngx_md5_t md5, ctx1;
+
+ /* Apache's apr1 crypt is Poul-Henning Kamp's md5 crypt with $apr1$ magic */
+
+ keylen = ngx_strlen(key);
+
+ /* true salt: no magic, max 8 chars, stop at first $ */
+
+ salt += sizeof("$apr1$") - 1;
+ last = salt + 8;
+ for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ }
+ saltlen = p - salt;
+
+ /* hash key and salt */
+
+ ngx_md5_init(&md5);
+ ngx_md5_update(&md5, key, keylen);
+ ngx_md5_update(&md5, (u_char *) "$apr1$", sizeof("$apr1$") - 1);
+ ngx_md5_update(&md5, salt, saltlen);
+
+ ngx_md5_init(&ctx1);
+ ngx_md5_update(&ctx1, key, keylen);
+ ngx_md5_update(&ctx1, salt, saltlen);
+ ngx_md5_update(&ctx1, key, keylen);
+ ngx_md5_final(final, &ctx1);
+
+ for (n = keylen; n > 0; n -= 16) {
+ ngx_md5_update(&md5, final, n > 16 ? 16 : n);
+ }
+
+ ngx_memzero(final, sizeof(final));
+
+ for (i = keylen; i; i >>= 1) {
+ if (i & 1) {
+ ngx_md5_update(&md5, final, 1);
+
+ } else {
+ ngx_md5_update(&md5, key, 1);
+ }
+ }
+
+ ngx_md5_final(final, &md5);
+
+ for (i = 0; i < 1000; i++) {
+ ngx_md5_init(&ctx1);
+
+ if (i & 1) {
+ ngx_md5_update(&ctx1, key, keylen);
+
+ } else {
+ ngx_md5_update(&ctx1, final, 16);
+ }
+
+ if (i % 3) {
+ ngx_md5_update(&ctx1, salt, saltlen);
+ }
+
+ if (i % 7) {
+ ngx_md5_update(&ctx1, key, keylen);
+ }
+
+ if (i & 1) {
+ ngx_md5_update(&ctx1, final, 16);
+
+ } else {
+ ngx_md5_update(&ctx1, key, keylen);
+ }
+
+ ngx_md5_final(final, &ctx1);
+ }
+
+ /* output */
+
+ *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 1 + 22 + 1);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1);
+ p = ngx_copy(p, salt, saltlen);
+ *p++ = '$';
+
+ p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4);
+ p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4);
+ p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4);
+ p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4);
+ p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4);
+ p = ngx_crypt_to64(p, final[11], 2);
+ *p = '\0';
+
+ return NGX_OK;
+}
+
+
+static u_char *
+ngx_crypt_to64(u_char *p, uint32_t v, size_t n)
+{
+ static u_char itoa64[] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (n--) {
+ *p++ = itoa64[v & 0x3f];
+ v >>= 6;
+ }
+
+ return p;
+}
+
+
+static ngx_int_t
+ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ size_t len;
+ u_char *p;
+
+ len = ngx_strlen(key);
+
+ *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1);
+ ngx_memcpy(p, key, len + 1);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ size_t len;
+ ngx_int_t rc;
+ ngx_str_t encoded, decoded;
+ ngx_sha1_t sha1;
+
+ /* "{SSHA}" base64(SHA1(key salt) salt) */
+
+ /* decode base64 salt to find out true salt */
+
+ encoded.data = salt + sizeof("{SSHA}") - 1;
+ encoded.len = ngx_strlen(encoded.data);
+
+ len = ngx_max(ngx_base64_decoded_length(encoded.len), 20);
+
+ decoded.data = ngx_pnalloc(pool, len);
+ if (decoded.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ rc = ngx_decode_base64(&decoded, &encoded);
+
+ if (rc != NGX_OK || decoded.len < 20) {
+ decoded.len = 20;
+ }
+
+ /* update SHA1 from key and salt */
+
+ ngx_sha1_init(&sha1);
+ ngx_sha1_update(&sha1, key, ngx_strlen(key));
+ ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20);
+ ngx_sha1_final(decoded.data, &sha1);
+
+ /* encode it back to base64 */
+
+ len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
+
+ *encrypted = ngx_pnalloc(pool, len);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1);
+ ngx_encode_base64(&encoded, &decoded);
+ encoded.data[encoded.len] = '\0';
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
+{
+ size_t len;
+ ngx_str_t encoded, decoded;
+ ngx_sha1_t sha1;
+ u_char digest[20];
+
+ /* "{SHA}" base64(SHA1(key)) */
+
+ decoded.len = sizeof(digest);
+ decoded.data = digest;
+
+ ngx_sha1_init(&sha1);
+ ngx_sha1_update(&sha1, key, ngx_strlen(key));
+ ngx_sha1_final(digest, &sha1);
+
+ len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1;
+
+ *encrypted = ngx_pnalloc(pool, len);
+ if (*encrypted == NULL) {
+ return NGX_ERROR;
+ }
+
+ encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1);
+ ngx_encode_base64(&encoded, &decoded);
+ encoded.data[encoded.len] = '\0';
+
+ return NGX_OK;
+}
+
+#endif /* NGX_CRYPT */
diff --git a/app/nginx/src/core/ngx_crypt.h b/app/nginx/src/core/ngx_crypt.h
new file mode 100644
index 0000000..3869114
--- /dev/null
+++ b/app/nginx/src/core/ngx_crypt.h
@@ -0,0 +1,20 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CRYPT_H_INCLUDED_
+#define _NGX_CRYPT_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt,
+ u_char **encrypted);
+
+
+#endif /* _NGX_CRYPT_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_cycle.c b/app/nginx/src/core/ngx_cycle.c
new file mode 100644
index 0000000..aee7a58
--- /dev/null
+++ b/app/nginx/src/core/ngx_cycle.c
@@ -0,0 +1,1384 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static void ngx_destroy_cycle_pools(ngx_conf_t *conf);
+static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle,
+ ngx_shm_zone_t *shm_zone);
+static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log);
+static void ngx_clean_old_cycles(ngx_event_t *ev);
+static void ngx_shutdown_timer_handler(ngx_event_t *ev);
+
+
+volatile ngx_cycle_t *ngx_cycle;
+ngx_array_t ngx_old_cycles;
+
+static ngx_pool_t *ngx_temp_pool;
+static ngx_event_t ngx_cleaner_event;
+static ngx_event_t ngx_shutdown_event;
+
+ngx_uint_t ngx_test_config;
+ngx_uint_t ngx_dump_config;
+ngx_uint_t ngx_quiet_mode;
+
+
+/* STUB NAME */
+static ngx_connection_t dumb;
+/* STUB */
+
+
+ngx_cycle_t *
+ngx_init_cycle(ngx_cycle_t *old_cycle)
+{
+ void *rv;
+ char **senv;
+ ngx_uint_t i, n;
+ ngx_log_t *log;
+ ngx_time_t *tp;
+ ngx_conf_t conf;
+ ngx_pool_t *pool;
+ ngx_cycle_t *cycle, **old;
+ ngx_shm_zone_t *shm_zone, *oshm_zone;
+ ngx_list_part_t *part, *opart;
+ ngx_open_file_t *file;
+ ngx_listening_t *ls, *nls;
+ ngx_core_conf_t *ccf, *old_ccf;
+ ngx_core_module_t *module;
+ char hostname[NGX_MAXHOSTNAMELEN];
+
+ ngx_timezone_update();
+
+ /* force localtime update with a new timezone */
+
+ tp = ngx_timeofday();
+ tp->sec = 0;
+
+ ngx_time_update();
+
+
+ log = old_cycle->log;
+
+ pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
+ if (pool == NULL) {
+ return NULL;
+ }
+ pool->log = log;
+
+ cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t));
+ if (cycle == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ cycle->pool = pool;
+ cycle->log = log;
+ cycle->old_cycle = old_cycle;
+
+ cycle->conf_prefix.len = old_cycle->conf_prefix.len;
+ cycle->conf_prefix.data = ngx_pstrdup(pool, &old_cycle->conf_prefix);
+ if (cycle->conf_prefix.data == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ cycle->prefix.len = old_cycle->prefix.len;
+ cycle->prefix.data = ngx_pstrdup(pool, &old_cycle->prefix);
+ if (cycle->prefix.data == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ cycle->conf_file.len = old_cycle->conf_file.len;
+ cycle->conf_file.data = ngx_pnalloc(pool, old_cycle->conf_file.len + 1);
+ if (cycle->conf_file.data == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+ ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
+ old_cycle->conf_file.len + 1);
+
+ cycle->conf_param.len = old_cycle->conf_param.len;
+ cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
+ if (cycle->conf_param.data == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+
+ n = old_cycle->paths.nelts ? old_cycle->paths.nelts : 10;
+
+ if (ngx_array_init(&cycle->paths, pool, n, sizeof(ngx_path_t *))
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ ngx_memzero(cycle->paths.elts, n * sizeof(ngx_path_t *));
+
+
+ if (ngx_array_init(&cycle->config_dump, pool, 1, sizeof(ngx_conf_dump_t))
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ ngx_rbtree_init(&cycle->config_dump_rbtree, &cycle->config_dump_sentinel,
+ ngx_str_rbtree_insert_value);
+
+ if (old_cycle->open_files.part.nelts) {
+ n = old_cycle->open_files.part.nelts;
+ for (part = old_cycle->open_files.part.next; part; part = part->next) {
+ n += part->nelts;
+ }
+
+ } else {
+ n = 20;
+ }
+
+ if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t))
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+
+ if (old_cycle->shared_memory.part.nelts) {
+ n = old_cycle->shared_memory.part.nelts;
+ for (part = old_cycle->shared_memory.part.next; part; part = part->next)
+ {
+ n += part->nelts;
+ }
+
+ } else {
+ n = 1;
+ }
+
+ if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t))
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10;
+
+ if (ngx_array_init(&cycle->listening, pool, n, sizeof(ngx_listening_t))
+ != NGX_OK)
+ {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ ngx_memzero(cycle->listening.elts, n * sizeof(ngx_listening_t));
+
+
+ ngx_queue_init(&cycle->reusable_connections_queue);
+
+
+ cycle->conf_ctx = ngx_pcalloc(pool, ngx_max_module * sizeof(void *));
+ if (cycle->conf_ctx == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+
+ if (gethostname(hostname, NGX_MAXHOSTNAMELEN) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostname() failed");
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ /* on Linux gethostname() silently truncates name that does not fit */
+
+ hostname[NGX_MAXHOSTNAMELEN - 1] = '\0';
+ cycle->hostname.len = ngx_strlen(hostname);
+
+ cycle->hostname.data = ngx_pnalloc(pool, cycle->hostname.len);
+ if (cycle->hostname.data == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len);
+
+
+ if (ngx_cycle_modules(cycle) != NGX_OK) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->type != NGX_CORE_MODULE) {
+ continue;
+ }
+
+ module = cycle->modules[i]->ctx;
+
+ if (module->create_conf) {
+ rv = module->create_conf(cycle);
+ if (rv == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+ cycle->conf_ctx[cycle->modules[i]->index] = rv;
+ }
+ }
+
+
+ senv = environ;
+
+
+ ngx_memzero(&conf, sizeof(ngx_conf_t));
+ /* STUB: init array ? */
+ conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t));
+ if (conf.args == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+ conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log);
+ if (conf.temp_pool == NULL) {
+ ngx_destroy_pool(pool);
+ return NULL;
+ }
+
+
+ conf.ctx = cycle->conf_ctx;
+ conf.cycle = cycle;
+ conf.pool = pool;
+ conf.log = log;
+ conf.module_type = NGX_CORE_MODULE;
+ conf.cmd_type = NGX_MAIN_CONF;
+
+#if 0
+ log->log_level = NGX_LOG_DEBUG_ALL;
+#endif
+
+ if (ngx_conf_param(&conf) != NGX_CONF_OK) {
+ environ = senv;
+ ngx_destroy_cycle_pools(&conf);
+ return NULL;
+ }
+
+ if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
+ environ = senv;
+ ngx_destroy_cycle_pools(&conf);
+ return NULL;
+ }
+
+ if (ngx_test_config && !ngx_quiet_mode) {
+ ngx_log_stderr(0, "the configuration file %s syntax is ok",
+ cycle->conf_file.data);
+ }
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->type != NGX_CORE_MODULE) {
+ continue;
+ }
+
+ module = cycle->modules[i]->ctx;
+
+ if (module->init_conf) {
+ if (module->init_conf(cycle,
+ cycle->conf_ctx[cycle->modules[i]->index])
+ == NGX_CONF_ERROR)
+ {
+ environ = senv;
+ ngx_destroy_cycle_pools(&conf);
+ return NULL;
+ }
+ }
+ }
+
+ if (ngx_process == NGX_PROCESS_SIGNALLER) {
+ return cycle;
+ }
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (ngx_test_config) {
+
+ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
+ goto failed;
+ }
+
+ } else if (!ngx_is_init_cycle(old_cycle)) {
+
+ /*
+ * we do not create the pid file in the first ngx_init_cycle() call
+ * because we need to write the demonized process pid
+ */
+
+ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
+ ngx_core_module);
+ if (ccf->pid.len != old_ccf->pid.len
+ || ngx_strcmp(ccf->pid.data, old_ccf->pid.data) != 0)
+ {
+ /* new pid file name */
+
+ if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_delete_pidfile(old_cycle);
+ }
+ }
+
+
+ if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) {
+ goto failed;
+ }
+
+
+ if (ngx_create_paths(cycle, ccf->user) != NGX_OK) {
+ goto failed;
+ }
+
+
+ if (ngx_log_open_default(cycle) != NGX_OK) {
+ goto failed;
+ }
+
+ /* open the new files */
+
+ part = &cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (file[i].name.len == 0) {
+ continue;
+ }
+
+ file[i].fd = ngx_open_file(file[i].name.data,
+ NGX_FILE_APPEND,
+ NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0,
+ "log: %p %d \"%s\"",
+ &file[i], file[i].fd, file[i].name.data);
+
+ if (file[i].fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed",
+ file[i].name.data);
+ goto failed;
+ }
+
+#if !(NGX_WIN32)
+ if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ "fcntl(FD_CLOEXEC) \"%s\" failed",
+ file[i].name.data);
+ goto failed;
+ }
+#endif
+ }
+
+ cycle->log = &cycle->new_log;
+ pool->log = &cycle->new_log;
+
+
+ /* create shared memory */
+
+ part = &cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ i = 0;
+ }
+
+ if (shm_zone[i].shm.size == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "zero size shared memory zone \"%V\"",
+ &shm_zone[i].shm.name);
+ goto failed;
+ }
+
+ shm_zone[i].shm.log = cycle->log;
+
+ opart = &old_cycle->shared_memory.part;
+ oshm_zone = opart->elts;
+
+ for (n = 0; /* void */ ; n++) {
+
+ if (n >= opart->nelts) {
+ if (opart->next == NULL) {
+ break;
+ }
+ opart = opart->next;
+ oshm_zone = opart->elts;
+ n = 0;
+ }
+
+ if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) {
+ continue;
+ }
+
+ if (ngx_strncmp(shm_zone[i].shm.name.data,
+ oshm_zone[n].shm.name.data,
+ shm_zone[i].shm.name.len)
+ != 0)
+ {
+ continue;
+ }
+
+ if (shm_zone[i].tag == oshm_zone[n].tag
+ && shm_zone[i].shm.size == oshm_zone[n].shm.size
+ && !shm_zone[i].noreuse)
+ {
+ shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
+#if (NGX_WIN32)
+ shm_zone[i].shm.handle = oshm_zone[n].shm.handle;
+#endif
+
+ if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ goto shm_zone_found;
+ }
+
+ ngx_shm_free(&oshm_zone[n].shm);
+
+ break;
+ }
+
+ if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
+ goto failed;
+ }
+
+ if (ngx_init_zone_pool(cycle, &shm_zone[i]) != NGX_OK) {
+ goto failed;
+ }
+
+ if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
+ goto failed;
+ }
+
+ shm_zone_found:
+
+ continue;
+ }
+
+
+ /* handle the listening sockets */
+
+ if (old_cycle->listening.nelts) {
+ ls = old_cycle->listening.elts;
+ for (i = 0; i < old_cycle->listening.nelts; i++) {
+ ls[i].remain = 0;
+ }
+
+ nls = cycle->listening.elts;
+ for (n = 0; n < cycle->listening.nelts; n++) {
+
+ for (i = 0; i < old_cycle->listening.nelts; i++) {
+ if (ls[i].ignore) {
+ continue;
+ }
+
+ if (ls[i].remain) {
+ continue;
+ }
+
+ if (ls[i].type != nls[n].type) {
+ continue;
+ }
+
+ if (ngx_cmp_sockaddr(nls[n].sockaddr, nls[n].socklen,
+ ls[i].sockaddr, ls[i].socklen, 1)
+ == NGX_OK)
+ {
+ nls[n].fd = ls[i].fd;
+ nls[n].previous = &ls[i];
+ ls[i].remain = 1;
+
+ if (ls[i].backlog != nls[n].backlog) {
+ nls[n].listen = 1;
+ }
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+
+ /*
+ * FreeBSD, except the most recent versions,
+ * could not remove accept filter
+ */
+ nls[n].deferred_accept = ls[i].deferred_accept;
+
+ if (ls[i].accept_filter && nls[n].accept_filter) {
+ if (ngx_strcmp(ls[i].accept_filter,
+ nls[n].accept_filter)
+ != 0)
+ {
+ nls[n].delete_deferred = 1;
+ nls[n].add_deferred = 1;
+ }
+
+ } else if (ls[i].accept_filter) {
+ nls[n].delete_deferred = 1;
+
+ } else if (nls[n].accept_filter) {
+ nls[n].add_deferred = 1;
+ }
+#endif
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+
+ if (ls[i].deferred_accept && !nls[n].deferred_accept) {
+ nls[n].delete_deferred = 1;
+
+ } else if (ls[i].deferred_accept != nls[n].deferred_accept)
+ {
+ nls[n].add_deferred = 1;
+ }
+#endif
+
+#if (NGX_HAVE_REUSEPORT)
+ if (nls[n].reuseport && !ls[i].reuseport) {
+ nls[n].add_reuseport = 1;
+ }
+#endif
+
+ break;
+ }
+ }
+
+ if (nls[n].fd == (ngx_socket_t) -1) {
+ nls[n].open = 1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ if (nls[n].accept_filter) {
+ nls[n].add_deferred = 1;
+ }
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ if (nls[n].deferred_accept) {
+ nls[n].add_deferred = 1;
+ }
+#endif
+ }
+ }
+
+ } else {
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+ ls[i].open = 1;
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+ if (ls[i].accept_filter) {
+ ls[i].add_deferred = 1;
+ }
+#endif
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
+ if (ls[i].deferred_accept) {
+ ls[i].add_deferred = 1;
+ }
+#endif
+ }
+ }
+
+ if (ngx_open_listening_sockets(cycle) != NGX_OK) {
+ goto failed;
+ }
+
+ if (!ngx_test_config) {
+ ngx_configure_listening_sockets(cycle);
+ }
+
+
+ /* commit the new cycle configuration */
+
+ if (!ngx_use_stderr) {
+ (void) ngx_log_redirect_stderr(cycle);
+ }
+
+ pool->log = cycle->log;
+
+ if (ngx_init_modules(cycle) != NGX_OK) {
+ /* fatal */
+ exit(1);
+ }
+
+
+ /* close and delete stuff that lefts from an old cycle */
+
+ /* free the unnecessary shared memory */
+
+ opart = &old_cycle->shared_memory.part;
+ oshm_zone = opart->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= opart->nelts) {
+ if (opart->next == NULL) {
+ goto old_shm_zone_done;
+ }
+ opart = opart->next;
+ oshm_zone = opart->elts;
+ i = 0;
+ }
+
+ part = &cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (n = 0; /* void */ ; n++) {
+
+ if (n >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ n = 0;
+ }
+
+ if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len
+ && ngx_strncmp(oshm_zone[i].shm.name.data,
+ shm_zone[n].shm.name.data,
+ oshm_zone[i].shm.name.len)
+ == 0)
+ {
+ goto live_shm_zone;
+ }
+ }
+
+ ngx_shm_free(&oshm_zone[i].shm);
+
+ live_shm_zone:
+
+ continue;
+ }
+
+old_shm_zone_done:
+
+
+ /* close the unnecessary listening sockets */
+
+ ls = old_cycle->listening.elts;
+ for (i = 0; i < old_cycle->listening.nelts; i++) {
+
+ if (ls[i].remain || ls[i].fd == (ngx_socket_t) -1) {
+ continue;
+ }
+
+ if (ngx_close_socket(ls[i].fd) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " listening socket on %V failed",
+ &ls[i].addr_text);
+ }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (ls[i].sockaddr->sa_family == AF_UNIX) {
+ u_char *name;
+
+ name = ls[i].addr_text.data + sizeof("unix:") - 1;
+
+ ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
+ "deleting socket %s", name);
+
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
+ ngx_delete_file_n " %s failed", name);
+ }
+ }
+
+#endif
+ }
+
+
+ /* close the unnecessary open files */
+
+ part = &old_cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
+ continue;
+ }
+
+ if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+ }
+
+ ngx_destroy_pool(conf.temp_pool);
+
+ if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
+
+ ngx_destroy_pool(old_cycle->pool);
+ cycle->old_cycle = NULL;
+
+ return cycle;
+ }
+
+
+ if (ngx_temp_pool == NULL) {
+ ngx_temp_pool = ngx_create_pool(128, cycle->log);
+ if (ngx_temp_pool == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "could not create ngx_temp_pool");
+ exit(1);
+ }
+
+ n = 10;
+
+ if (ngx_array_init(&ngx_old_cycles, ngx_temp_pool, n,
+ sizeof(ngx_cycle_t *))
+ != NGX_OK)
+ {
+ exit(1);
+ }
+
+ ngx_memzero(ngx_old_cycles.elts, n * sizeof(ngx_cycle_t *));
+
+ ngx_cleaner_event.handler = ngx_clean_old_cycles;
+ ngx_cleaner_event.log = cycle->log;
+ ngx_cleaner_event.data = &dumb;
+ dumb.fd = (ngx_socket_t) -1;
+ }
+
+ ngx_temp_pool->log = cycle->log;
+
+ old = ngx_array_push(&ngx_old_cycles);
+ if (old == NULL) {
+ exit(1);
+ }
+ *old = old_cycle;
+
+ if (!ngx_cleaner_event.timer_set) {
+ ngx_add_timer(&ngx_cleaner_event, 30000);
+ ngx_cleaner_event.timer_set = 1;
+ }
+
+ return cycle;
+
+
+failed:
+
+ if (!ngx_is_init_cycle(old_cycle)) {
+ old_ccf = (ngx_core_conf_t *) ngx_get_conf(old_cycle->conf_ctx,
+ ngx_core_module);
+ if (old_ccf->environment) {
+ environ = old_ccf->environment;
+ }
+ }
+
+ /* rollback the new cycle configuration */
+
+ part = &cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (file[i].fd == NGX_INVALID_FILE || file[i].fd == ngx_stderr) {
+ continue;
+ }
+
+ if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+ }
+
+ if (ngx_test_config) {
+ ngx_destroy_cycle_pools(&conf);
+ return NULL;
+ }
+
+ ls = cycle->listening.elts;
+ for (i = 0; i < cycle->listening.nelts; i++) {
+ if (ls[i].fd == (ngx_socket_t) -1 || !ls[i].open) {
+ continue;
+ }
+
+ if (ngx_close_socket(ls[i].fd) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+ ngx_close_socket_n " %V failed",
+ &ls[i].addr_text);
+ }
+ }
+
+ ngx_destroy_cycle_pools(&conf);
+
+ return NULL;
+}
+
+
+static void
+ngx_destroy_cycle_pools(ngx_conf_t *conf)
+{
+ ngx_destroy_pool(conf->temp_pool);
+ ngx_destroy_pool(conf->pool);
+}
+
+
+static ngx_int_t
+ngx_init_zone_pool(ngx_cycle_t *cycle, ngx_shm_zone_t *zn)
+{
+ u_char *file;
+ ngx_slab_pool_t *sp;
+
+ sp = (ngx_slab_pool_t *) zn->shm.addr;
+
+ if (zn->shm.exists) {
+
+ if (sp == sp->addr) {
+ return NGX_OK;
+ }
+
+#if (NGX_WIN32)
+
+ /* remap at the required address */
+
+ if (ngx_shm_remap(&zn->shm, sp->addr) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ sp = (ngx_slab_pool_t *) zn->shm.addr;
+
+ if (sp == sp->addr) {
+ return NGX_OK;
+ }
+
+#endif
+
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "shared zone \"%V\" has no equal addresses: %p vs %p",
+ &zn->shm.name, sp->addr, sp);
+ return NGX_ERROR;
+ }
+
+ sp->end = zn->shm.addr + zn->shm.size;
+ sp->min_shift = 3;
+ sp->addr = zn->shm.addr;
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+ file = NULL;
+
+#else
+
+ file = ngx_pnalloc(cycle->pool, cycle->lock_file.len + zn->shm.name.len);
+ if (file == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_sprintf(file, "%V%V%Z", &cycle->lock_file, &zn->shm.name);
+
+#endif
+
+ if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ ngx_slab_init(sp);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
+{
+ size_t len;
+ ngx_uint_t create;
+ ngx_file_t file;
+ u_char pid[NGX_INT64_LEN + 2];
+
+ if (ngx_process > NGX_PROCESS_MASTER) {
+ return NGX_OK;
+ }
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+
+ file.name = *name;
+ file.log = log;
+
+ create = ngx_test_config ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE;
+
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
+ create, NGX_FILE_DEFAULT_ACCESS);
+
+ if (file.fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file.name.data);
+ return NGX_ERROR;
+ }
+
+ if (!ngx_test_config) {
+ len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid;
+
+ if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file.name.data);
+ }
+
+ return NGX_OK;
+}
+
+
+void
+ngx_delete_pidfile(ngx_cycle_t *cycle)
+{
+ u_char *name;
+ ngx_core_conf_t *ccf;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ name = ngx_new_binary ? ccf->oldpid.data : ccf->pid.data;
+
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed", name);
+ }
+}
+
+
+ngx_int_t
+ngx_signal_process(ngx_cycle_t *cycle, char *sig)
+{
+ ssize_t n;
+ ngx_pid_t pid;
+ ngx_file_t file;
+ ngx_core_conf_t *ccf;
+ u_char buf[NGX_INT64_LEN + 2];
+
+ ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started");
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ ngx_memzero(&file, sizeof(ngx_file_t));
+
+ file.name = ccf->pid;
+ file.log = cycle->log;
+
+ file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY,
+ NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS);
+
+ if (file.fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file.name.data);
+ return 1;
+ }
+
+ n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0);
+
+ if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file.name.data);
+ }
+
+ if (n == NGX_ERROR) {
+ return 1;
+ }
+
+ while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ }
+
+ pid = ngx_atoi(buf, ++n);
+
+ if (pid == (ngx_pid_t) NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ERR, cycle->log, 0,
+ "invalid PID number \"%*s\" in \"%s\"",
+ n, buf, file.name.data);
+ return 1;
+ }
+
+ return ngx_os_signal_process(cycle, sig, pid);
+
+}
+
+
+static ngx_int_t
+ngx_test_lockfile(u_char *file, ngx_log_t *log)
+{
+#if !(NGX_HAVE_ATOMIC_OPS)
+ ngx_fd_t fd;
+
+ fd = ngx_open_file(file, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS);
+
+ if (fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file);
+ return NGX_ERROR;
+ }
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file);
+ }
+
+ if (ngx_delete_file(file) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed", file);
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+void
+ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
+{
+ ngx_fd_t fd;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_open_file_t *file;
+
+ part = &cycle->open_files.part;
+ file = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ file = part->elts;
+ i = 0;
+ }
+
+ if (file[i].name.len == 0) {
+ continue;
+ }
+
+ if (file[i].flush) {
+ file[i].flush(&file[i], cycle->log);
+ }
+
+ fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND,
+ NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "reopen file \"%s\", old:%d new:%d",
+ file[i].name.data, file[i].fd, fd);
+
+ if (fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", file[i].name.data);
+ continue;
+ }
+
+#if !(NGX_WIN32)
+ if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
+ ngx_file_info_t fi;
+
+ if (ngx_file_info((const char *) file[i].name.data, &fi)
+ == NGX_FILE_ERROR)
+ {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_file_info_n " \"%s\" failed",
+ file[i].name.data);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+
+ continue;
+ }
+
+ if (fi.st_uid != user) {
+ if (chown((const char *) file[i].name.data, user, -1) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "chown(\"%s\", %d) failed",
+ file[i].name.data, user);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+
+ continue;
+ }
+ }
+
+ if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {
+
+ fi.st_mode |= (S_IRUSR|S_IWUSR);
+
+ if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "chmod() \"%s\" failed", file[i].name.data);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+
+ continue;
+ }
+ }
+ }
+
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "fcntl(FD_CLOEXEC) \"%s\" failed",
+ file[i].name.data);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+
+ continue;
+ }
+#endif
+
+ if (ngx_close_file(file[i].fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ file[i].name.data);
+ }
+
+ file[i].fd = fd;
+ }
+
+ (void) ngx_log_redirect_stderr(cycle);
+}
+
+
+ngx_shm_zone_t *
+ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
+{
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_list_part_t *part;
+
+ part = &cf->cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ i = 0;
+ }
+
+ if (name->len != shm_zone[i].shm.name.len) {
+ continue;
+ }
+
+ if (ngx_strncmp(name->data, shm_zone[i].shm.name.data, name->len)
+ != 0)
+ {
+ continue;
+ }
+
+ if (tag != shm_zone[i].tag) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the shared memory zone \"%V\" is "
+ "already declared for a different use",
+ &shm_zone[i].shm.name);
+ return NULL;
+ }
+
+ if (shm_zone[i].shm.size == 0) {
+ shm_zone[i].shm.size = size;
+ }
+
+ if (size && size != shm_zone[i].shm.size) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the size %uz of shared memory zone \"%V\" "
+ "conflicts with already declared size %uz",
+ size, &shm_zone[i].shm.name, shm_zone[i].shm.size);
+ return NULL;
+ }
+
+ return &shm_zone[i];
+ }
+
+ shm_zone = ngx_list_push(&cf->cycle->shared_memory);
+
+ if (shm_zone == NULL) {
+ return NULL;
+ }
+
+ shm_zone->data = NULL;
+ shm_zone->shm.log = cf->cycle->log;
+ shm_zone->shm.size = size;
+ shm_zone->shm.name = *name;
+ shm_zone->shm.exists = 0;
+ shm_zone->init = NULL;
+ shm_zone->tag = tag;
+ shm_zone->noreuse = 0;
+
+ return shm_zone;
+}
+
+
+static void
+ngx_clean_old_cycles(ngx_event_t *ev)
+{
+ ngx_uint_t i, n, found, live;
+ ngx_log_t *log;
+ ngx_cycle_t **cycle;
+
+ log = ngx_cycle->log;
+ ngx_temp_pool->log = log;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycles");
+
+ live = 0;
+
+ cycle = ngx_old_cycles.elts;
+ for (i = 0; i < ngx_old_cycles.nelts; i++) {
+
+ if (cycle[i] == NULL) {
+ continue;
+ }
+
+ found = 0;
+
+ for (n = 0; n < cycle[i]->connection_n; n++) {
+ if (cycle[i]->connections[n].fd != (ngx_socket_t) -1) {
+ found = 1;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "live fd:%ui", n);
+
+ break;
+ }
+ }
+
+ if (found) {
+ live = 1;
+ continue;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "clean old cycle: %ui", i);
+
+ ngx_destroy_pool(cycle[i]->pool);
+ cycle[i] = NULL;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, "old cycles status: %ui", live);
+
+ if (live) {
+ ngx_add_timer(ev, 30000);
+
+ } else {
+ ngx_destroy_pool(ngx_temp_pool);
+ ngx_temp_pool = NULL;
+ ngx_old_cycles.nelts = 0;
+ }
+}
+
+
+void
+ngx_set_shutdown_timer(ngx_cycle_t *cycle)
+{
+ ngx_core_conf_t *ccf;
+
+ ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+ if (ccf->shutdown_timeout) {
+ ngx_shutdown_event.handler = ngx_shutdown_timer_handler;
+ ngx_shutdown_event.data = cycle;
+ ngx_shutdown_event.log = cycle->log;
+ ngx_shutdown_event.cancelable = 1;
+
+ ngx_add_timer(&ngx_shutdown_event, ccf->shutdown_timeout);
+ }
+}
+
+
+static void
+ngx_shutdown_timer_handler(ngx_event_t *ev)
+{
+ ngx_uint_t i;
+ ngx_cycle_t *cycle;
+ ngx_connection_t *c;
+
+ cycle = ev->data;
+
+ c = cycle->connections;
+
+ for (i = 0; i < cycle->connection_n; i++) {
+
+ if (c[i].fd == (ngx_socket_t) -1
+ || c[i].read == NULL
+ || c[i].read->accept
+ || c[i].read->channel
+ || c[i].read->resolver)
+ {
+ continue;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "*%uA shutdown timeout", c[i].number);
+
+ c[i].close = 1;
+ c[i].error = 1;
+
+ c[i].read->handler(c[i].read);
+ }
+}
diff --git a/app/nginx/src/core/ngx_cycle.h b/app/nginx/src/core/ngx_cycle.h
new file mode 100644
index 0000000..2b48ccb
--- /dev/null
+++ b/app/nginx/src/core/ngx_cycle.h
@@ -0,0 +1,144 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_CYCLE_H_INCLUDED_
+#define _NGX_CYCLE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#ifndef NGX_CYCLE_POOL_SIZE
+#define NGX_CYCLE_POOL_SIZE NGX_DEFAULT_POOL_SIZE
+#endif
+
+
+#define NGX_DEBUG_POINTS_STOP 1
+#define NGX_DEBUG_POINTS_ABORT 2
+
+
+typedef struct ngx_shm_zone_s ngx_shm_zone_t;
+
+typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);
+
+struct ngx_shm_zone_s {
+ void *data;
+ ngx_shm_t shm;
+ ngx_shm_zone_init_pt init;
+ void *tag;
+ ngx_uint_t noreuse; /* unsigned noreuse:1; */
+};
+
+
+struct ngx_cycle_s {
+ void ****conf_ctx;
+ ngx_pool_t *pool;
+
+ ngx_log_t *log;
+ ngx_log_t new_log;
+
+ ngx_uint_t log_use_stderr; /* unsigned log_use_stderr:1; */
+
+ ngx_connection_t **files;
+ ngx_connection_t *free_connections;
+ ngx_uint_t free_connection_n;
+
+ ngx_module_t **modules;
+ ngx_uint_t modules_n;
+ ngx_uint_t modules_used; /* unsigned modules_used:1; */
+
+ ngx_queue_t reusable_connections_queue;
+ ngx_uint_t reusable_connections_n;
+
+ ngx_array_t listening;
+ ngx_array_t paths;
+
+ ngx_array_t config_dump;
+ ngx_rbtree_t config_dump_rbtree;
+ ngx_rbtree_node_t config_dump_sentinel;
+
+ ngx_list_t open_files;
+ ngx_list_t shared_memory;
+
+ ngx_uint_t connection_n;
+ ngx_uint_t files_n;
+
+ ngx_connection_t *connections;
+ ngx_event_t *read_events;
+ ngx_event_t *write_events;
+
+ ngx_cycle_t *old_cycle;
+
+ ngx_str_t conf_file;
+ ngx_str_t conf_param;
+ ngx_str_t conf_prefix;
+ ngx_str_t prefix;
+ ngx_str_t lock_file;
+ ngx_str_t hostname;
+};
+
+
+typedef struct {
+ ngx_flag_t daemon;
+ ngx_flag_t master;
+
+ ngx_msec_t timer_resolution;
+ ngx_msec_t shutdown_timeout;
+
+ ngx_int_t worker_processes;
+ ngx_int_t debug_points;
+
+ ngx_int_t rlimit_nofile;
+ off_t rlimit_core;
+
+ int priority;
+
+ ngx_uint_t cpu_affinity_auto;
+ ngx_uint_t cpu_affinity_n;
+ ngx_cpuset_t *cpu_affinity;
+
+ char *username;
+ ngx_uid_t user;
+ ngx_gid_t group;
+
+ ngx_str_t working_directory;
+ ngx_str_t lock_file;
+
+ ngx_str_t pid;
+ ngx_str_t oldpid;
+
+ ngx_array_t env;
+ char **environment;
+} ngx_core_conf_t;
+
+
+#define ngx_is_init_cycle(cycle) (cycle->conf_ctx == NULL)
+
+
+ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle);
+ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
+void ngx_delete_pidfile(ngx_cycle_t *cycle);
+ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig);
+void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
+char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
+ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
+ngx_cpuset_t *ngx_get_cpu_affinity(ngx_uint_t n);
+ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
+ size_t size, void *tag);
+void ngx_set_shutdown_timer(ngx_cycle_t *cycle);
+
+
+extern volatile ngx_cycle_t *ngx_cycle;
+extern ngx_array_t ngx_old_cycles;
+extern ngx_module_t ngx_core_module;
+extern ngx_uint_t ngx_test_config;
+extern ngx_uint_t ngx_dump_config;
+extern ngx_uint_t ngx_quiet_mode;
+
+
+#endif /* _NGX_CYCLE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_file.c b/app/nginx/src/core/ngx_file.c
new file mode 100644
index 0000000..b7dd4bc
--- /dev/null
+++ b/app/nginx/src/core/ngx_file.c
@@ -0,0 +1,1127 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static ngx_int_t ngx_test_full_name(ngx_str_t *name);
+
+
+static ngx_atomic_t temp_number = 0;
+ngx_atomic_t *ngx_temp_number = &temp_number;
+ngx_atomic_int_t ngx_random_number = 123456;
+
+
+ngx_int_t
+ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix, ngx_str_t *name)
+{
+ size_t len;
+ u_char *p, *n;
+ ngx_int_t rc;
+
+ rc = ngx_test_full_name(name);
+
+ if (rc == NGX_OK) {
+ return rc;
+ }
+
+ len = prefix->len;
+
+#if (NGX_WIN32)
+
+ if (rc == 2) {
+ len = rc;
+ }
+
+#endif
+
+ n = ngx_pnalloc(pool, len + name->len + 1);
+ if (n == NULL) {
+ return NGX_ERROR;
+ }
+
+ p = ngx_cpymem(n, prefix->data, len);
+ ngx_cpystrn(p, name->data, name->len + 1);
+
+ name->len += len;
+ name->data = n;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_test_full_name(ngx_str_t *name)
+{
+#if (NGX_WIN32)
+ u_char c0, c1;
+
+ c0 = name->data[0];
+
+ if (name->len < 2) {
+ if (c0 == '/') {
+ return 2;
+ }
+
+ return NGX_DECLINED;
+ }
+
+ c1 = name->data[1];
+
+ if (c1 == ':') {
+ c0 |= 0x20;
+
+ if ((c0 >= 'a' && c0 <= 'z')) {
+ return NGX_OK;
+ }
+
+ return NGX_DECLINED;
+ }
+
+ if (c1 == '/') {
+ return NGX_OK;
+ }
+
+ if (c0 == '/') {
+ return 2;
+ }
+
+ return NGX_DECLINED;
+
+#else
+
+ if (name->data[0] == '/') {
+ return NGX_OK;
+ }
+
+ return NGX_DECLINED;
+
+#endif
+}
+
+
+ssize_t
+ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain)
+{
+ ngx_int_t rc;
+
+ if (tf->file.fd == NGX_INVALID_FILE) {
+ rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
+ tf->persistent, tf->clean, tf->access);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ if (tf->log_level) {
+ ngx_log_error(tf->log_level, tf->file.log, 0, "%s %V",
+ tf->warn, &tf->file.name);
+ }
+ }
+
+#if (NGX_THREADS && NGX_HAVE_PWRITEV)
+
+ if (tf->thread_write) {
+ return ngx_thread_write_chain_to_file(&tf->file, chain, tf->offset,
+ tf->pool);
+ }
+
+#endif
+
+ return ngx_write_chain_to_file(&tf->file, chain, tf->offset, tf->pool);
+}
+
+
+ngx_int_t
+ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
+ ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
+{
+ size_t levels;
+ u_char *p;
+ uint32_t n;
+ ngx_err_t err;
+ ngx_str_t name;
+ ngx_uint_t prefix;
+ ngx_pool_cleanup_t *cln;
+ ngx_pool_cleanup_file_t *clnf;
+
+ if (file->name.len) {
+ name = file->name;
+ levels = 0;
+ prefix = 1;
+
+ } else {
+ name = path->name;
+ levels = path->len;
+ prefix = 0;
+ }
+
+ file->name.len = name.len + 1 + levels + 10;
+
+ file->name.data = ngx_pnalloc(pool, file->name.len + 1);
+ if (file->name.data == NULL) {
+ return NGX_ERROR;
+ }
+
+#if 0
+ for (i = 0; i < file->name.len; i++) {
+ file->name.data[i] = 'X';
+ }
+#endif
+
+ p = ngx_cpymem(file->name.data, name.data, name.len);
+
+ if (prefix) {
+ *p = '.';
+ }
+
+ p += 1 + levels;
+
+ n = (uint32_t) ngx_next_temp_number(0);
+
+ cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ for ( ;; ) {
+ (void) ngx_sprintf(p, "%010uD%Z", n);
+
+ if (!prefix) {
+ ngx_create_hashed_filename(path, file->name.data, file->name.len);
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "hashed path: %s", file->name.data);
+
+ file->fd = ngx_open_tempfile(file->name.data, persistent, access);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "temp fd:%d", file->fd);
+
+ if (file->fd != NGX_INVALID_FILE) {
+
+ cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
+ clnf = cln->data;
+
+ clnf->fd = file->fd;
+ clnf->name = file->name.data;
+ clnf->log = pool->log;
+
+ return NGX_OK;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_EEXIST_FILE) {
+ n = (uint32_t) ngx_next_temp_number(1);
+ continue;
+ }
+
+ if ((path->level[0] == 0) || (err != NGX_ENOPATH)) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ ngx_open_tempfile_n " \"%s\" failed",
+ file->name.data);
+ return NGX_ERROR;
+ }
+
+ if (ngx_create_path(file, path) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ }
+}
+
+
+void
+ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len)
+{
+ size_t i, level;
+ ngx_uint_t n;
+
+ i = path->name.len + 1;
+
+ file[path->name.len + path->len] = '/';
+
+ for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
+ level = path->level[n];
+
+ if (level == 0) {
+ break;
+ }
+
+ len -= level;
+ file[i - 1] = '/';
+ ngx_memcpy(&file[i], &file[len], level);
+ i += level + 1;
+ }
+}
+
+
+ngx_int_t
+ngx_create_path(ngx_file_t *file, ngx_path_t *path)
+{
+ size_t pos;
+ ngx_err_t err;
+ ngx_uint_t i;
+
+ pos = path->name.len;
+
+ for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) {
+ if (path->level[i] == 0) {
+ break;
+ }
+
+ pos += path->level[i] + 1;
+
+ file->name.data[pos] = '\0';
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
+ "temp file: \"%s\"", file->name.data);
+
+ if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+ if (err != NGX_EEXIST) {
+ ngx_log_error(NGX_LOG_CRIT, file->log, err,
+ ngx_create_dir_n " \"%s\" failed",
+ file->name.data);
+ return NGX_ERROR;
+ }
+ }
+
+ file->name.data[pos] = '/';
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_err_t
+ngx_create_full_path(u_char *dir, ngx_uint_t access)
+{
+ u_char *p, ch;
+ ngx_err_t err;
+
+ err = 0;
+
+#if (NGX_WIN32)
+ p = dir + 3;
+#else
+ p = dir + 1;
+#endif
+
+ for ( /* void */ ; *p; p++) {
+ ch = *p;
+
+ if (ch != '/') {
+ continue;
+ }
+
+ *p = '\0';
+
+ if (ngx_create_dir(dir, access) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+
+ switch (err) {
+ case NGX_EEXIST:
+ err = 0;
+ case NGX_EACCES:
+ break;
+
+ default:
+ return err;
+ }
+ }
+
+ *p = '/';
+ }
+
+ return err;
+}
+
+
+ngx_atomic_uint_t
+ngx_next_temp_number(ngx_uint_t collision)
+{
+ ngx_atomic_uint_t n, add;
+
+ add = collision ? ngx_random_number : 1;
+
+ n = ngx_atomic_fetch_add(ngx_temp_number, add);
+
+ return n + add;
+}
+
+
+char *
+ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ssize_t level;
+ ngx_str_t *value;
+ ngx_uint_t i, n;
+ ngx_path_t *path, **slot;
+
+ slot = (ngx_path_t **) (p + cmd->offset);
+
+ if (*slot) {
+ return "is duplicate";
+ }
+
+ path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
+ if (path == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ path->name = value[1];
+
+ if (path->name.data[path->name.len - 1] == '/') {
+ path->name.len--;
+ }
+
+ if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ path->conf_file = cf->conf_file->file.name.data;
+ path->line = cf->conf_file->line;
+
+ for (i = 0, n = 2; n < cf->args->nelts; i++, n++) {
+ level = ngx_atoi(value[n].data, value[n].len);
+ if (level == NGX_ERROR || level == 0) {
+ return "invalid value";
+ }
+
+ path->level[i] = level;
+ path->len += level + 1;
+ }
+
+ if (path->len > 10 + i) {
+ return "invalid value";
+ }
+
+ *slot = path;
+
+ if (ngx_add_path(cf, slot) == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
+ ngx_path_init_t *init)
+{
+ ngx_uint_t i;
+
+ if (*path) {
+ return NGX_CONF_OK;
+ }
+
+ if (prev) {
+ *path = prev;
+ return NGX_CONF_OK;
+ }
+
+ *path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
+ if (*path == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ (*path)->name = init->name;
+
+ if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; i < NGX_MAX_PATH_LEVEL; i++) {
+ (*path)->level[i] = init->level[i];
+ (*path)->len += init->level[i] + (init->level[i] ? 1 : 0);
+ }
+
+ if (ngx_add_path(cf, path) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *confp = conf;
+
+ u_char *p;
+ ngx_str_t *value;
+ ngx_uint_t i, right, shift, *access, user;
+
+ access = (ngx_uint_t *) (confp + cmd->offset);
+
+ if (*access != NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *access = 0;
+ user = 0600;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ p = value[i].data;
+
+ if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
+ shift = 6;
+ p += sizeof("user:") - 1;
+ user = 0;
+
+ } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
+ shift = 3;
+ p += sizeof("group:") - 1;
+
+ } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
+ shift = 0;
+ p += sizeof("all:") - 1;
+
+ } else {
+ goto invalid;
+ }
+
+ if (ngx_strcmp(p, "rw") == 0) {
+ right = 6;
+
+ } else if (ngx_strcmp(p, "r") == 0) {
+ right = 4;
+
+ } else {
+ goto invalid;
+ }
+
+ *access |= right << shift;
+ }
+
+ *access |= user;
+
+ return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
+
+ return NGX_CONF_ERROR;
+}
+
+
+ngx_int_t
+ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
+{
+ ngx_uint_t i, n;
+ ngx_path_t *path, **p;
+
+ path = *slot;
+
+ p = cf->cycle->paths.elts;
+ for (i = 0; i < cf->cycle->paths.nelts; i++) {
+ if (p[i]->name.len == path->name.len
+ && ngx_strcmp(p[i]->name.data, path->name.data) == 0)
+ {
+ if (p[i]->data != path->data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the same path name \"%V\" "
+ "used in %s:%ui and",
+ &p[i]->name, p[i]->conf_file, p[i]->line);
+ return NGX_ERROR;
+ }
+
+ for (n = 0; n < NGX_MAX_PATH_LEVEL; n++) {
+ if (p[i]->level[n] != path->level[n]) {
+ if (path->conf_file == NULL) {
+ if (p[i]->conf_file == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "the default path name \"%V\" has "
+ "the same name as another default path, "
+ "but the different levels, you need to "
+ "redefine one of them in http section",
+ &p[i]->name);
+ return NGX_ERROR;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "the path name \"%V\" in %s:%ui has "
+ "the same name as default path, but "
+ "the different levels, you need to "
+ "define default path in http section",
+ &p[i]->name, p[i]->conf_file, p[i]->line);
+ return NGX_ERROR;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the same path name \"%V\" in %s:%ui "
+ "has the different levels than",
+ &p[i]->name, p[i]->conf_file, p[i]->line);
+ return NGX_ERROR;
+ }
+
+ if (p[i]->level[n] == 0) {
+ break;
+ }
+ }
+
+ *slot = p[i];
+
+ return NGX_OK;
+ }
+ }
+
+ p = ngx_array_push(&cf->cycle->paths);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ *p = path;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user)
+{
+ ngx_err_t err;
+ ngx_uint_t i;
+ ngx_path_t **path;
+
+ path = cycle->paths.elts;
+ for (i = 0; i < cycle->paths.nelts; i++) {
+
+ if (ngx_create_dir(path[i]->name.data, 0700) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+ if (err != NGX_EEXIST) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, err,
+ ngx_create_dir_n " \"%s\" failed",
+ path[i]->name.data);
+ return NGX_ERROR;
+ }
+ }
+
+ if (user == (ngx_uid_t) NGX_CONF_UNSET_UINT) {
+ continue;
+ }
+
+#if !(NGX_WIN32)
+ {
+ ngx_file_info_t fi;
+
+ if (ngx_file_info((const char *) path[i]->name.data, &fi)
+ == NGX_FILE_ERROR)
+ {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ ngx_file_info_n " \"%s\" failed", path[i]->name.data);
+ return NGX_ERROR;
+ }
+
+ if (fi.st_uid != user) {
+ if (chown((const char *) path[i]->name.data, user, -1) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "chown(\"%s\", %d) failed",
+ path[i]->name.data, user);
+ return NGX_ERROR;
+ }
+ }
+
+ if ((fi.st_mode & (S_IRUSR|S_IWUSR|S_IXUSR))
+ != (S_IRUSR|S_IWUSR|S_IXUSR))
+ {
+ fi.st_mode |= (S_IRUSR|S_IWUSR|S_IXUSR);
+
+ if (chmod((const char *) path[i]->name.data, fi.st_mode) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+ "chmod() \"%s\" failed", path[i]->name.data);
+ return NGX_ERROR;
+ }
+ }
+ }
+#endif
+ }
+
+ return NGX_OK;
+}
+
+
+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;
+}
+
+
+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;
+}
+
+
+/*
+ * ctx->init_handler() - see ctx->alloc
+ * ctx->file_handler() - file handler
+ * ctx->pre_tree_handler() - handler is called before entering directory
+ * ctx->post_tree_handler() - handler is called after leaving directory
+ * ctx->spec_handler() - special (socket, FIFO, etc.) file handler
+ *
+ * ctx->data - some data structure, it may be the same on all levels, or
+ * reallocated if ctx->alloc is nonzero
+ *
+ * ctx->alloc - a size of data structure that is allocated at every level
+ * and is initialized by ctx->init_handler()
+ *
+ * ctx->log - a log
+ *
+ * on fatal (memory) error handler must return NGX_ABORT to stop walking tree
+ */
+
+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;
+
+ ngx_str_null(&buf);
+
+ 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->fs_size = ngx_de_fs_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);
+
+ rc = ctx->pre_tree_handler(ctx, &file);
+
+ if (rc == NGX_ABORT) {
+ goto failed;
+ }
+
+ if (rc == NGX_DECLINED) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree skip dir \"%s\"", file.data);
+ continue;
+ }
+
+ 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;
+}
diff --git a/app/nginx/src/core/ngx_file.h b/app/nginx/src/core/ngx_file.h
new file mode 100644
index 0000000..320adc2
--- /dev/null
+++ b/app/nginx/src/core/ngx_file.h
@@ -0,0 +1,164 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_FILE_H_INCLUDED_
+#define _NGX_FILE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+struct ngx_file_s {
+ ngx_fd_t fd;
+ ngx_str_t name;
+ ngx_file_info_t info;
+
+ off_t offset;
+ off_t sys_offset;
+
+ ngx_log_t *log;
+
+#if (NGX_THREADS || NGX_COMPAT)
+ ngx_int_t (*thread_handler)(ngx_thread_task_t *task,
+ ngx_file_t *file);
+ void *thread_ctx;
+ ngx_thread_task_t *thread_task;
+#endif
+
+#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
+ ngx_event_aio_t *aio;
+#endif
+
+ unsigned valid_info:1;
+ unsigned directio:1;
+};
+
+
+#define NGX_MAX_PATH_LEVEL 3
+
+
+typedef ngx_msec_t (*ngx_path_manager_pt) (void *data);
+typedef ngx_msec_t (*ngx_path_purger_pt) (void *data);
+typedef void (*ngx_path_loader_pt) (void *data);
+
+
+typedef struct {
+ ngx_str_t name;
+ size_t len;
+ size_t level[NGX_MAX_PATH_LEVEL];
+
+ ngx_path_manager_pt manager;
+ ngx_path_purger_pt purger;
+ ngx_path_loader_pt loader;
+ void *data;
+
+ u_char *conf_file;
+ ngx_uint_t line;
+} ngx_path_t;
+
+
+typedef struct {
+ ngx_str_t name;
+ size_t level[NGX_MAX_PATH_LEVEL];
+} ngx_path_init_t;
+
+
+typedef struct {
+ ngx_file_t file;
+ off_t offset;
+ ngx_path_t *path;
+ ngx_pool_t *pool;
+ char *warn;
+
+ ngx_uint_t access;
+
+ unsigned log_level:8;
+ unsigned persistent:1;
+ unsigned clean:1;
+ unsigned thread_write:1;
+} ngx_temp_file_t;
+
+
+typedef struct {
+ ngx_uint_t access;
+ ngx_uint_t path_access;
+ time_t time;
+ ngx_fd_t fd;
+
+ unsigned create_path:1;
+ unsigned delete_file:1;
+
+ ngx_log_t *log;
+} ngx_ext_rename_file_t;
+
+
+typedef struct {
+ off_t size;
+ size_t buf_size;
+
+ ngx_uint_t access;
+ time_t time;
+
+ ngx_log_t *log;
+} ngx_copy_file_t;
+
+
+typedef struct ngx_tree_ctx_s ngx_tree_ctx_t;
+
+typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev);
+typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name);
+
+struct ngx_tree_ctx_s {
+ off_t size;
+ off_t fs_size;
+ ngx_uint_t access;
+ time_t mtime;
+
+ ngx_tree_init_handler_pt init_handler;
+ ngx_tree_handler_pt file_handler;
+ ngx_tree_handler_pt pre_tree_handler;
+ ngx_tree_handler_pt post_tree_handler;
+ ngx_tree_handler_pt spec_handler;
+
+ void *data;
+ size_t alloc;
+
+ ngx_log_t *log;
+};
+
+
+ngx_int_t ngx_get_full_name(ngx_pool_t *pool, ngx_str_t *prefix,
+ ngx_str_t *name);
+
+ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
+ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
+ ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
+ ngx_uint_t access);
+void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t len);
+ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
+ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
+ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
+ngx_int_t ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user);
+ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to,
+ ngx_ext_rename_file_t *ext);
+ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf);
+ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
+
+ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
+
+char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path,
+ ngx_path_t *prev, ngx_path_init_t *init);
+char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+
+extern ngx_atomic_t *ngx_temp_number;
+extern ngx_atomic_int_t ngx_random_number;
+
+
+#endif /* _NGX_FILE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_hash.c b/app/nginx/src/core/ngx_hash.c
new file mode 100644
index 0000000..1944c7a
--- /dev/null
+++ b/app/nginx/src/core/ngx_hash.c
@@ -0,0 +1,988 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void *
+ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
+{
+ ngx_uint_t i;
+ ngx_hash_elt_t *elt;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name);
+#endif
+
+ elt = hash->buckets[key % hash->size];
+
+ if (elt == NULL) {
+ return NULL;
+ }
+
+ while (elt->value) {
+ if (len != (size_t) elt->len) {
+ goto next;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (name[i] != elt->name[i]) {
+ goto next;
+ }
+ }
+
+ return elt->value;
+
+ next:
+
+ elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
+ sizeof(void *));
+ continue;
+ }
+
+ return NULL;
+}
+
+
+void *
+ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
+{
+ void *value;
+ ngx_uint_t i, n, key;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name);
+#endif
+
+ n = len;
+
+ while (n) {
+ if (name[n - 1] == '.') {
+ break;
+ }
+
+ n--;
+ }
+
+ key = 0;
+
+ for (i = n; i < len; i++) {
+ key = ngx_hash(key, name[i]);
+ }
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
+#endif
+
+ value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
+#endif
+
+ if (value) {
+
+ /*
+ * the 2 low bits of value have the special meaning:
+ * 00 - value is data pointer for both "example.com"
+ * and "*.example.com";
+ * 01 - value is data pointer for "*.example.com" only;
+ * 10 - value is pointer to wildcard hash allowing
+ * both "example.com" and "*.example.com";
+ * 11 - value is pointer to wildcard hash allowing
+ * "*.example.com" only.
+ */
+
+ if ((uintptr_t) value & 2) {
+
+ if (n == 0) {
+
+ /* "example.com" */
+
+ if ((uintptr_t) value & 1) {
+ return NULL;
+ }
+
+ hwc = (ngx_hash_wildcard_t *)
+ ((uintptr_t) value & (uintptr_t) ~3);
+ return hwc->value;
+ }
+
+ hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
+
+ value = ngx_hash_find_wc_head(hwc, name, n - 1);
+
+ if (value) {
+ return value;
+ }
+
+ return hwc->value;
+ }
+
+ if ((uintptr_t) value & 1) {
+
+ if (n == 0) {
+
+ /* "example.com" */
+
+ return NULL;
+ }
+
+ return (void *) ((uintptr_t) value & (uintptr_t) ~3);
+ }
+
+ return value;
+ }
+
+ return hwc->value;
+}
+
+
+void *
+ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
+{
+ void *value;
+ ngx_uint_t i, key;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%*s\"", len, name);
+#endif
+
+ key = 0;
+
+ for (i = 0; i < len; i++) {
+ if (name[i] == '.') {
+ break;
+ }
+
+ key = ngx_hash(key, name[i]);
+ }
+
+ if (i == len) {
+ return NULL;
+ }
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
+#endif
+
+ value = ngx_hash_find(&hwc->hash, key, name, i);
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
+#endif
+
+ if (value) {
+
+ /*
+ * the 2 low bits of value have the special meaning:
+ * 00 - value is data pointer;
+ * 11 - value is pointer to wildcard hash allowing "example.*".
+ */
+
+ if ((uintptr_t) value & 2) {
+
+ i++;
+
+ hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
+
+ value = ngx_hash_find_wc_tail(hwc, &name[i], len - i);
+
+ if (value) {
+ return value;
+ }
+
+ return hwc->value;
+ }
+
+ return value;
+ }
+
+ return hwc->value;
+}
+
+
+void *
+ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,
+ size_t len)
+{
+ void *value;
+
+ if (hash->hash.buckets) {
+ value = ngx_hash_find(&hash->hash, key, name, len);
+
+ if (value) {
+ return value;
+ }
+ }
+
+ if (len == 0) {
+ return NULL;
+ }
+
+ if (hash->wc_head && hash->wc_head->hash.buckets) {
+ value = ngx_hash_find_wc_head(hash->wc_head, name, len);
+
+ if (value) {
+ return value;
+ }
+ }
+
+ if (hash->wc_tail && hash->wc_tail->hash.buckets) {
+ value = ngx_hash_find_wc_tail(hash->wc_tail, name, len);
+
+ if (value) {
+ return value;
+ }
+ }
+
+ return NULL;
+}
+
+
+#define NGX_HASH_ELT_SIZE(name) \
+ (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
+
+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;
+
+ if (hinit->max_size == 0) {
+ ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
+ "could not build %s, you should "
+ "increase %s_max_size: %i",
+ hinit->name, hinit->name, hinit->max_size);
+ return NGX_ERROR;
+ }
+
+ for (n = 0; n < nelts; n++) {
+ 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 %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 && 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 = hinit->max_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_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
+ ngx_uint_t nelts)
+{
+ size_t len, dot_len;
+ ngx_uint_t i, n, dot;
+ ngx_array_t curr_names, next_names;
+ ngx_hash_key_t *name, *next_name;
+ ngx_hash_init_t h;
+ ngx_hash_wildcard_t *wdc;
+
+ if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
+ sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
+ sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ for (n = 0; n < nelts; n = i) {
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
+ "wc0: \"%V\"", &names[n].key);
+#endif
+
+ dot = 0;
+
+ for (len = 0; len < names[n].key.len; len++) {
+ if (names[n].key.data[len] == '.') {
+ dot = 1;
+ break;
+ }
+ }
+
+ name = ngx_array_push(&curr_names);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
+
+ name->key.len = len;
+ name->key.data = names[n].key.data;
+ name->key_hash = hinit->key(name->key.data, name->key.len);
+ name->value = names[n].value;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
+ "wc1: \"%V\" %ui", &name->key, dot);
+#endif
+
+ dot_len = len + 1;
+
+ if (dot) {
+ len++;
+ }
+
+ next_names.nelts = 0;
+
+ if (names[n].key.len != len) {
+ next_name = ngx_array_push(&next_names);
+ if (next_name == NULL) {
+ return NGX_ERROR;
+ }
+
+ next_name->key.len = names[n].key.len - len;
+ next_name->key.data = names[n].key.data + len;
+ next_name->key_hash = 0;
+ next_name->value = names[n].value;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
+ "wc2: \"%V\"", &next_name->key);
+#endif
+ }
+
+ for (i = n + 1; i < nelts; i++) {
+ if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
+ break;
+ }
+
+ if (!dot
+ && names[i].key.len > len
+ && names[i].key.data[len] != '.')
+ {
+ break;
+ }
+
+ next_name = ngx_array_push(&next_names);
+ if (next_name == NULL) {
+ return NGX_ERROR;
+ }
+
+ next_name->key.len = names[i].key.len - dot_len;
+ next_name->key.data = names[i].key.data + dot_len;
+ next_name->key_hash = 0;
+ next_name->value = names[i].value;
+
+#if 0
+ ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
+ "wc3: \"%V\"", &next_name->key);
+#endif
+ }
+
+ if (next_names.nelts) {
+
+ h = *hinit;
+ h.hash = NULL;
+
+ if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
+ next_names.nelts)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ wdc = (ngx_hash_wildcard_t *) h.hash;
+
+ if (names[n].key.len == len) {
+ wdc->value = names[n].value;
+ }
+
+ name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2));
+
+ } else if (dot) {
+ name->value = (void *) ((uintptr_t) name->value | 1);
+ }
+ }
+
+ if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
+ curr_names.nelts)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_uint_t
+ngx_hash_key(u_char *data, size_t len)
+{
+ ngx_uint_t i, key;
+
+ key = 0;
+
+ for (i = 0; i < len; i++) {
+ key = ngx_hash(key, data[i]);
+ }
+
+ return key;
+}
+
+
+ngx_uint_t
+ngx_hash_key_lc(u_char *data, size_t len)
+{
+ ngx_uint_t i, key;
+
+ key = 0;
+
+ for (i = 0; i < len; i++) {
+ key = ngx_hash(key, ngx_tolower(data[i]));
+ }
+
+ return key;
+}
+
+
+ngx_uint_t
+ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
+{
+ ngx_uint_t key;
+
+ key = 0;
+
+ while (n--) {
+ *dst = ngx_tolower(*src);
+ key = ngx_hash(key, *dst);
+ dst++;
+ src++;
+ }
+
+ return key;
+}
+
+
+ngx_int_t
+ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
+{
+ ngx_uint_t asize;
+
+ if (type == NGX_HASH_SMALL) {
+ asize = 4;
+ ha->hsize = 107;
+
+ } else {
+ asize = NGX_HASH_LARGE_ASIZE;
+ ha->hsize = NGX_HASH_LARGE_HSIZE;
+ }
+
+ if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize,
+ sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize,
+ sizeof(ngx_hash_key_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
+ if (ha->keys_hash == NULL) {
+ return NGX_ERROR;
+ }
+
+ ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool,
+ sizeof(ngx_array_t) * ha->hsize);
+ if (ha->dns_wc_head_hash == NULL) {
+ return NGX_ERROR;
+ }
+
+ ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool,
+ sizeof(ngx_array_t) * ha->hsize);
+ if (ha->dns_wc_tail_hash == NULL) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
+ ngx_uint_t flags)
+{
+ size_t len;
+ u_char *p;
+ ngx_str_t *name;
+ ngx_uint_t i, k, n, skip, last;
+ ngx_array_t *keys, *hwc;
+ ngx_hash_key_t *hk;
+
+ last = key->len;
+
+ if (flags & NGX_HASH_WILDCARD_KEY) {
+
+ /*
+ * supported wildcards:
+ * "*.example.com", ".example.com", and "www.example.*"
+ */
+
+ n = 0;
+
+ for (i = 0; i < key->len; i++) {
+
+ if (key->data[i] == '*') {
+ if (++n > 1) {
+ return NGX_DECLINED;
+ }
+ }
+
+ if (key->data[i] == '.' && key->data[i + 1] == '.') {
+ return NGX_DECLINED;
+ }
+
+ if (key->data[i] == '\0') {
+ return NGX_DECLINED;
+ }
+ }
+
+ if (key->len > 1 && key->data[0] == '.') {
+ skip = 1;
+ goto wildcard;
+ }
+
+ if (key->len > 2) {
+
+ if (key->data[0] == '*' && key->data[1] == '.') {
+ skip = 2;
+ goto wildcard;
+ }
+
+ if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
+ skip = 0;
+ last -= 2;
+ goto wildcard;
+ }
+ }
+
+ if (n) {
+ return NGX_DECLINED;
+ }
+ }
+
+ /* exact hash */
+
+ k = 0;
+
+ for (i = 0; i < last; i++) {
+ if (!(flags & NGX_HASH_READONLY_KEY)) {
+ key->data[i] = ngx_tolower(key->data[i]);
+ }
+ k = ngx_hash(k, key->data[i]);
+ }
+
+ k %= ha->hsize;
+
+ /* check conflicts in exact hash */
+
+ name = ha->keys_hash[k].elts;
+
+ if (name) {
+ for (i = 0; i < ha->keys_hash[k].nelts; i++) {
+ if (last != name[i].len) {
+ continue;
+ }
+
+ if (ngx_strncmp(key->data, name[i].data, last) == 0) {
+ return NGX_BUSY;
+ }
+ }
+
+ } else {
+ if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+ sizeof(ngx_str_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ name = ngx_array_push(&ha->keys_hash[k]);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
+
+ *name = *key;
+
+ hk = ngx_array_push(&ha->keys);
+ if (hk == NULL) {
+ return NGX_ERROR;
+ }
+
+ hk->key = *key;
+ hk->key_hash = ngx_hash_key(key->data, last);
+ hk->value = value;
+
+ return NGX_OK;
+
+
+wildcard:
+
+ /* wildcard hash */
+
+ k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip);
+
+ k %= ha->hsize;
+
+ if (skip == 1) {
+
+ /* check conflicts in exact hash for ".example.com" */
+
+ name = ha->keys_hash[k].elts;
+
+ if (name) {
+ len = last - skip;
+
+ for (i = 0; i < ha->keys_hash[k].nelts; i++) {
+ if (len != name[i].len) {
+ continue;
+ }
+
+ if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
+ return NGX_BUSY;
+ }
+ }
+
+ } else {
+ if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+ sizeof(ngx_str_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ name = ngx_array_push(&ha->keys_hash[k]);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
+
+ name->len = last - 1;
+ name->data = ngx_pnalloc(ha->temp_pool, name->len);
+ if (name->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(name->data, &key->data[1], name->len);
+ }
+
+
+ if (skip) {
+
+ /*
+ * convert "*.example.com" to "com.example.\0"
+ * and ".example.com" to "com.example\0"
+ */
+
+ p = ngx_pnalloc(ha->temp_pool, last);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ len = 0;
+ n = 0;
+
+ for (i = last - 1; i; i--) {
+ if (key->data[i] == '.') {
+ ngx_memcpy(&p[n], &key->data[i + 1], len);
+ n += len;
+ p[n++] = '.';
+ len = 0;
+ continue;
+ }
+
+ len++;
+ }
+
+ if (len) {
+ ngx_memcpy(&p[n], &key->data[1], len);
+ n += len;
+ }
+
+ p[n] = '\0';
+
+ hwc = &ha->dns_wc_head;
+ keys = &ha->dns_wc_head_hash[k];
+
+ } else {
+
+ /* convert "www.example.*" to "www.example\0" */
+
+ last++;
+
+ p = ngx_pnalloc(ha->temp_pool, last);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_cpystrn(p, key->data, last);
+
+ hwc = &ha->dns_wc_tail;
+ keys = &ha->dns_wc_tail_hash[k];
+ }
+
+
+ /* check conflicts in wildcard hash */
+
+ name = keys->elts;
+
+ if (name) {
+ len = last - skip;
+
+ for (i = 0; i < keys->nelts; i++) {
+ if (len != name[i].len) {
+ continue;
+ }
+
+ if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
+ return NGX_BUSY;
+ }
+ }
+
+ } else {
+ if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ name = ngx_array_push(keys);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
+
+ name->len = last - skip;
+ name->data = ngx_pnalloc(ha->temp_pool, name->len);
+ if (name->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(name->data, key->data + skip, name->len);
+
+
+ /* add to wildcard hash */
+
+ hk = ngx_array_push(hwc);
+ if (hk == NULL) {
+ return NGX_ERROR;
+ }
+
+ hk->key.len = last - 1;
+ hk->key.data = p;
+ hk->key_hash = 0;
+ hk->value = value;
+
+ return NGX_OK;
+}
diff --git a/app/nginx/src/core/ngx_hash.h b/app/nginx/src/core/ngx_hash.h
new file mode 100644
index 0000000..abc3cbe
--- /dev/null
+++ b/app/nginx/src/core/ngx_hash.h
@@ -0,0 +1,122 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_HASH_H_INCLUDED_
+#define _NGX_HASH_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ void *value;
+ u_short len;
+ u_char name[1];
+} ngx_hash_elt_t;
+
+
+typedef struct {
+ ngx_hash_elt_t **buckets;
+ ngx_uint_t size;
+} ngx_hash_t;
+
+
+typedef struct {
+ ngx_hash_t hash;
+ void *value;
+} ngx_hash_wildcard_t;
+
+
+typedef struct {
+ ngx_str_t key;
+ ngx_uint_t key_hash;
+ void *value;
+} ngx_hash_key_t;
+
+
+typedef ngx_uint_t (*ngx_hash_key_pt) (u_char *data, size_t len);
+
+
+typedef struct {
+ ngx_hash_t hash;
+ ngx_hash_wildcard_t *wc_head;
+ ngx_hash_wildcard_t *wc_tail;
+} ngx_hash_combined_t;
+
+
+typedef struct {
+ ngx_hash_t *hash;
+ ngx_hash_key_pt key;
+
+ ngx_uint_t max_size;
+ ngx_uint_t bucket_size;
+
+ char *name;
+ ngx_pool_t *pool;
+ ngx_pool_t *temp_pool;
+} ngx_hash_init_t;
+
+
+#define NGX_HASH_SMALL 1
+#define NGX_HASH_LARGE 2
+
+#define NGX_HASH_LARGE_ASIZE 16384
+#define NGX_HASH_LARGE_HSIZE 10007
+
+#define NGX_HASH_WILDCARD_KEY 1
+#define NGX_HASH_READONLY_KEY 2
+
+
+typedef struct {
+ ngx_uint_t hsize;
+
+ ngx_pool_t *pool;
+ ngx_pool_t *temp_pool;
+
+ ngx_array_t keys;
+ ngx_array_t *keys_hash;
+
+ ngx_array_t dns_wc_head;
+ ngx_array_t *dns_wc_head_hash;
+
+ ngx_array_t dns_wc_tail;
+ ngx_array_t *dns_wc_tail_hash;
+} ngx_hash_keys_arrays_t;
+
+
+typedef struct {
+ ngx_uint_t hash;
+ ngx_str_t key;
+ ngx_str_t value;
+ u_char *lowcase_key;
+} ngx_table_elt_t;
+
+
+void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len);
+void *ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
+void *ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len);
+void *ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key,
+ u_char *name, size_t len);
+
+ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
+ ngx_uint_t nelts);
+ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
+ ngx_uint_t nelts);
+
+#define ngx_hash(key, c) ((ngx_uint_t) key * 31 + c)
+ngx_uint_t ngx_hash_key(u_char *data, size_t len);
+ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len);
+ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n);
+
+
+ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);
+ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
+ void *value, ngx_uint_t flags);
+
+
+#endif /* _NGX_HASH_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_inet.c b/app/nginx/src/core/ngx_inet.c
new file mode 100644
index 0000000..3bcd3e7
--- /dev/null
+++ b/app/nginx/src/core/ngx_inet.c
@@ -0,0 +1,1493 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u);
+static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u);
+static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u);
+
+
+in_addr_t
+ngx_inet_addr(u_char *text, size_t len)
+{
+ u_char *p, c;
+ in_addr_t addr;
+ ngx_uint_t octet, n;
+
+ addr = 0;
+ octet = 0;
+ n = 0;
+
+ for (p = text; p < text + len; p++) {
+ c = *p;
+
+ if (c >= '0' && c <= '9') {
+ octet = octet * 10 + (c - '0');
+
+ if (octet > 255) {
+ return INADDR_NONE;
+ }
+
+ continue;
+ }
+
+ if (c == '.') {
+ addr = (addr << 8) + octet;
+ octet = 0;
+ n++;
+ continue;
+ }
+
+ return INADDR_NONE;
+ }
+
+ if (n == 3) {
+ addr = (addr << 8) + octet;
+ return htonl(addr);
+ }
+
+ return INADDR_NONE;
+}
+
+
+#if (NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_inet6_addr(u_char *p, size_t len, u_char *addr)
+{
+ u_char c, *zero, *digit, *s, *d;
+ size_t len4;
+ ngx_uint_t n, nibbles, word;
+
+ if (len == 0) {
+ return NGX_ERROR;
+ }
+
+ zero = NULL;
+ digit = NULL;
+ len4 = 0;
+ nibbles = 0;
+ word = 0;
+ n = 8;
+
+ if (p[0] == ':') {
+ p++;
+ len--;
+ }
+
+ for (/* void */; len; len--) {
+ c = *p++;
+
+ if (c == ':') {
+ if (nibbles) {
+ digit = p;
+ len4 = len;
+ *addr++ = (u_char) (word >> 8);
+ *addr++ = (u_char) (word & 0xff);
+
+ if (--n) {
+ nibbles = 0;
+ word = 0;
+ continue;
+ }
+
+ } else {
+ if (zero == NULL) {
+ digit = p;
+ len4 = len;
+ zero = addr;
+ continue;
+ }
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (c == '.' && nibbles) {
+ if (n < 2 || digit == NULL) {
+ return NGX_ERROR;
+ }
+
+ word = ngx_inet_addr(digit, len4 - 1);
+ if (word == INADDR_NONE) {
+ return NGX_ERROR;
+ }
+
+ word = ntohl(word);
+ *addr++ = (u_char) ((word >> 24) & 0xff);
+ *addr++ = (u_char) ((word >> 16) & 0xff);
+ n--;
+ break;
+ }
+
+ if (++nibbles > 4) {
+ return NGX_ERROR;
+ }
+
+ if (c >= '0' && c <= '9') {
+ word = word * 16 + (c - '0');
+ continue;
+ }
+
+ c |= 0x20;
+
+ if (c >= 'a' && c <= 'f') {
+ word = word * 16 + (c - 'a') + 10;
+ continue;
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (nibbles == 0 && zero == NULL) {
+ return NGX_ERROR;
+ }
+
+ *addr++ = (u_char) (word >> 8);
+ *addr++ = (u_char) (word & 0xff);
+
+ if (--n) {
+ if (zero) {
+ n *= 2;
+ s = addr - 1;
+ d = s + n;
+ while (s >= zero) {
+ *d-- = *s--;
+ }
+ ngx_memzero(zero, n);
+ return NGX_OK;
+ }
+
+ } else {
+ if (zero == NULL) {
+ return NGX_OK;
+ }
+ }
+
+ return NGX_ERROR;
+}
+
+#endif
+
+
+size_t
+ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len,
+ ngx_uint_t port)
+{
+ u_char *p;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ size_t n;
+ struct sockaddr_in6 *sin6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ struct sockaddr_un *saun;
+#endif
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+
+ sin = (struct sockaddr_in *) sa;
+ p = (u_char *) &sin->sin_addr;
+
+ if (port) {
+ p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d",
+ p[0], p[1], p[2], p[3], ntohs(sin->sin_port));
+ } else {
+ p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
+ p[0], p[1], p[2], p[3]);
+ }
+
+ return (p - text);
+
+#if (NGX_HAVE_INET6)
+
+ case AF_INET6:
+
+ sin6 = (struct sockaddr_in6 *) sa;
+
+ n = 0;
+
+ if (port) {
+ text[n++] = '[';
+ }
+
+ n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len);
+
+ if (port) {
+ n = ngx_sprintf(&text[1 + n], "]:%d",
+ ntohs(sin6->sin6_port)) - text;
+ }
+
+ return n;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ case AF_UNIX:
+ saun = (struct sockaddr_un *) sa;
+
+ /* on Linux sockaddr might not include sun_path at all */
+
+ if (socklen <= (socklen_t) offsetof(struct sockaddr_un, sun_path)) {
+ p = ngx_snprintf(text, len, "unix:%Z");
+
+ } else {
+ p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path);
+ }
+
+ /* we do not include trailing zero in address length */
+
+ return (p - text - 1);
+
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+
+size_t
+ngx_inet_ntop(int family, void *addr, u_char *text, size_t len)
+{
+ u_char *p;
+
+ switch (family) {
+
+ case AF_INET:
+
+ p = addr;
+
+ return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud",
+ p[0], p[1], p[2], p[3])
+ - text;
+
+#if (NGX_HAVE_INET6)
+
+ case AF_INET6:
+ return ngx_inet6_ntop(addr, text, len);
+
+#endif
+
+ default:
+ return 0;
+ }
+}
+
+
+#if (NGX_HAVE_INET6)
+
+size_t
+ngx_inet6_ntop(u_char *p, u_char *text, size_t len)
+{
+ u_char *dst;
+ size_t max, n;
+ ngx_uint_t i, zero, last;
+
+ if (len < NGX_INET6_ADDRSTRLEN) {
+ return 0;
+ }
+
+ zero = (ngx_uint_t) -1;
+ last = (ngx_uint_t) -1;
+ max = 1;
+ n = 0;
+
+ for (i = 0; i < 16; i += 2) {
+
+ if (p[i] || p[i + 1]) {
+
+ if (max < n) {
+ zero = last;
+ max = n;
+ }
+
+ n = 0;
+ continue;
+ }
+
+ if (n++ == 0) {
+ last = i;
+ }
+ }
+
+ if (max < n) {
+ zero = last;
+ max = n;
+ }
+
+ dst = text;
+ n = 16;
+
+ if (zero == 0) {
+
+ if ((max == 5 && p[10] == 0xff && p[11] == 0xff)
+ || (max == 6)
+ || (max == 7 && p[14] != 0 && p[15] != 1))
+ {
+ n = 12;
+ }
+
+ *dst++ = ':';
+ }
+
+ for (i = 0; i < n; i += 2) {
+
+ if (i == zero) {
+ *dst++ = ':';
+ i += (max - 1) * 2;
+ continue;
+ }
+
+ dst = ngx_sprintf(dst, "%xd", p[i] * 256 + p[i + 1]);
+
+ if (i < 14) {
+ *dst++ = ':';
+ }
+ }
+
+ if (n == 12) {
+ dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]);
+ }
+
+ return dst - text;
+}
+
+#endif
+
+
+ngx_int_t
+ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr)
+{
+ u_char *addr, *mask, *last;
+ size_t len;
+ ngx_int_t shift;
+#if (NGX_HAVE_INET6)
+ ngx_int_t rc;
+ ngx_uint_t s, i;
+#endif
+
+ addr = text->data;
+ last = addr + text->len;
+
+ mask = ngx_strlchr(addr, last, '/');
+ len = (mask ? mask : last) - addr;
+
+ cidr->u.in.addr = ngx_inet_addr(addr, len);
+
+ if (cidr->u.in.addr != INADDR_NONE) {
+ cidr->family = AF_INET;
+
+ if (mask == NULL) {
+ cidr->u.in.mask = 0xffffffff;
+ return NGX_OK;
+ }
+
+#if (NGX_HAVE_INET6)
+ } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) {
+ cidr->family = AF_INET6;
+
+ if (mask == NULL) {
+ ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16);
+ return NGX_OK;
+ }
+
+#endif
+ } else {
+ return NGX_ERROR;
+ }
+
+ mask++;
+
+ shift = ngx_atoi(mask, last - mask);
+ if (shift == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ switch (cidr->family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ if (shift > 128) {
+ return NGX_ERROR;
+ }
+
+ addr = cidr->u.in6.addr.s6_addr;
+ mask = cidr->u.in6.mask.s6_addr;
+ rc = NGX_OK;
+
+ for (i = 0; i < 16; i++) {
+
+ s = (shift > 8) ? 8 : shift;
+ shift -= s;
+
+ mask[i] = (u_char) (0xffu << (8 - s));
+
+ if (addr[i] != (addr[i] & mask[i])) {
+ rc = NGX_DONE;
+ addr[i] &= mask[i];
+ }
+ }
+
+ return rc;
+#endif
+
+ default: /* AF_INET */
+ if (shift > 32) {
+ return NGX_ERROR;
+ }
+
+ if (shift) {
+ cidr->u.in.mask = htonl((uint32_t) (0xffffffffu << (32 - shift)));
+
+ } else {
+ /* x86 compilers use a shl instruction that shifts by modulo 32 */
+ cidr->u.in.mask = 0;
+ }
+
+ if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) {
+ return NGX_OK;
+ }
+
+ cidr->u.in.addr &= cidr->u.in.mask;
+
+ return NGX_DONE;
+ }
+}
+
+
+ngx_int_t
+ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs)
+{
+#if (NGX_HAVE_INET6)
+ u_char *p;
+#endif
+ in_addr_t inaddr;
+ ngx_cidr_t *cidr;
+ ngx_uint_t family, i;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t n;
+ struct in6_addr *inaddr6;
+#endif
+
+#if (NGX_SUPPRESS_WARN)
+ inaddr = 0;
+#if (NGX_HAVE_INET6)
+ inaddr6 = NULL;
+#endif
+#endif
+
+ family = sa->sa_family;
+
+ if (family == AF_INET) {
+ inaddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr;
+ }
+
+#if (NGX_HAVE_INET6)
+ else if (family == AF_INET6) {
+ inaddr6 = &((struct sockaddr_in6 *) sa)->sin6_addr;
+
+ if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
+ family = AF_INET;
+
+ p = inaddr6->s6_addr;
+
+ inaddr = p[12] << 24;
+ inaddr += p[13] << 16;
+ inaddr += p[14] << 8;
+ inaddr += p[15];
+
+ inaddr = htonl(inaddr);
+ }
+ }
+#endif
+
+ for (cidr = cidrs->elts, i = 0; i < cidrs->nelts; i++) {
+ if (cidr[i].family != family) {
+ goto next;
+ }
+
+ switch (family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ for (n = 0; n < 16; n++) {
+ if ((inaddr6->s6_addr[n] & cidr[i].u.in6.mask.s6_addr[n])
+ != cidr[i].u.in6.addr.s6_addr[n])
+ {
+ goto next;
+ }
+ }
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ break;
+#endif
+
+ default: /* AF_INET */
+ if ((inaddr & cidr[i].u.in.mask) != cidr[i].u.in.addr) {
+ goto next;
+ }
+ break;
+ }
+
+ return NGX_OK;
+
+ next:
+ continue;
+ }
+
+ return NGX_DECLINED;
+}
+
+
+ngx_int_t
+ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len)
+{
+ in_addr_t inaddr;
+ ngx_uint_t family;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct in6_addr inaddr6;
+ struct sockaddr_in6 *sin6;
+
+ /*
+ * prevent MSVC8 warning:
+ * potentially uninitialized local variable 'inaddr6' used
+ */
+ ngx_memzero(&inaddr6, sizeof(struct in6_addr));
+#endif
+
+ inaddr = ngx_inet_addr(text, len);
+
+ if (inaddr != INADDR_NONE) {
+ family = AF_INET;
+ len = sizeof(struct sockaddr_in);
+
+#if (NGX_HAVE_INET6)
+ } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) {
+ family = AF_INET6;
+ len = sizeof(struct sockaddr_in6);
+
+#endif
+ } else {
+ return NGX_DECLINED;
+ }
+
+ addr->sockaddr = ngx_pcalloc(pool, len);
+ if (addr->sockaddr == NULL) {
+ return NGX_ERROR;
+ }
+
+ addr->sockaddr->sa_family = (u_char) family;
+ addr->socklen = len;
+
+ switch (family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) addr->sockaddr;
+ ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16);
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) addr->sockaddr;
+ sin->sin_addr.s_addr = inaddr;
+ break;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
+ size_t len)
+{
+ u_char *p, *last;
+ size_t plen;
+ ngx_int_t rc, port;
+
+ rc = ngx_parse_addr(pool, addr, text, len);
+
+ if (rc != NGX_DECLINED) {
+ return rc;
+ }
+
+ last = text + len;
+
+#if (NGX_HAVE_INET6)
+ if (len && text[0] == '[') {
+
+ p = ngx_strlchr(text, last, ']');
+
+ if (p == NULL || p == last - 1 || *++p != ':') {
+ return NGX_DECLINED;
+ }
+
+ text++;
+ len -= 2;
+
+ } else
+#endif
+
+ {
+ p = ngx_strlchr(text, last, ':');
+
+ if (p == NULL) {
+ return NGX_DECLINED;
+ }
+ }
+
+ p++;
+ plen = last - p;
+
+ port = ngx_atoi(p, plen);
+
+ if (port < 1 || port > 65535) {
+ return NGX_DECLINED;
+ }
+
+ len -= plen + 1;
+
+ rc = ngx_parse_addr(pool, addr, text, len);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ ngx_inet_set_port(addr->sockaddr, (in_port_t) port);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+ u_char *p;
+ size_t len;
+
+ p = u->url.data;
+ len = u->url.len;
+
+ if (len >= 5 && ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) {
+ return ngx_parse_unix_domain_url(pool, u);
+ }
+
+ if (len && p[0] == '[') {
+ return ngx_parse_inet6_url(pool, u);
+ }
+
+ return ngx_parse_inet_url(pool, u);
+}
+
+
+static ngx_int_t
+ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+#if (NGX_HAVE_UNIX_DOMAIN)
+ u_char *path, *uri, *last;
+ size_t len;
+ struct sockaddr_un *saun;
+
+ len = u->url.len;
+ path = u->url.data;
+
+ path += 5;
+ len -= 5;
+
+ if (u->uri_part) {
+
+ last = path + len;
+ uri = ngx_strlchr(path, last, ':');
+
+ if (uri) {
+ len = uri - path;
+ uri++;
+ u->uri.len = last - uri;
+ u->uri.data = uri;
+ }
+ }
+
+ if (len == 0) {
+ u->err = "no path in the unix domain socket";
+ return NGX_ERROR;
+ }
+
+ u->host.len = len++;
+ u->host.data = path;
+
+ if (len > sizeof(saun->sun_path)) {
+ u->err = "too long path in the unix domain socket";
+ return NGX_ERROR;
+ }
+
+ u->socklen = sizeof(struct sockaddr_un);
+ saun = (struct sockaddr_un *) &u->sockaddr;
+ saun->sun_family = AF_UNIX;
+ (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
+
+ u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un));
+ if (saun == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->family = AF_UNIX;
+ u->naddrs = 1;
+
+ saun->sun_family = AF_UNIX;
+ (void) ngx_cpystrn((u_char *) saun->sun_path, path, len);
+
+ u->addrs[0].sockaddr = (struct sockaddr *) saun;
+ u->addrs[0].socklen = sizeof(struct sockaddr_un);
+ u->addrs[0].name.len = len + 4;
+ u->addrs[0].name.data = u->url.data;
+
+ return NGX_OK;
+
+#else
+
+ u->err = "the unix domain sockets are not supported on this platform";
+
+ return NGX_ERROR;
+
+#endif
+}
+
+
+static ngx_int_t
+ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+ u_char *p, *host, *port, *last, *uri, *args;
+ size_t len;
+ ngx_int_t n;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ u->socklen = sizeof(struct sockaddr_in);
+ sin = (struct sockaddr_in *) &u->sockaddr;
+ sin->sin_family = AF_INET;
+
+ u->family = AF_INET;
+
+ host = u->url.data;
+
+ last = host + u->url.len;
+
+ port = ngx_strlchr(host, last, ':');
+
+ uri = ngx_strlchr(host, last, '/');
+
+ args = ngx_strlchr(host, last, '?');
+
+ if (args) {
+ if (uri == NULL || args < uri) {
+ uri = args;
+ }
+ }
+
+ if (uri) {
+ if (u->listen || !u->uri_part) {
+ u->err = "invalid host";
+ return NGX_ERROR;
+ }
+
+ u->uri.len = last - uri;
+ u->uri.data = uri;
+
+ last = uri;
+
+ if (uri < port) {
+ port = NULL;
+ }
+ }
+
+ if (port) {
+ port++;
+
+ len = last - port;
+
+ n = ngx_atoi(port, len);
+
+ if (n < 1 || n > 65535) {
+ u->err = "invalid port";
+ return NGX_ERROR;
+ }
+
+ u->port = (in_port_t) n;
+ sin->sin_port = htons((in_port_t) n);
+
+ u->port_text.len = len;
+ u->port_text.data = port;
+
+ last = port - 1;
+
+ } else {
+ if (uri == NULL) {
+
+ if (u->listen) {
+
+ /* test value as port only */
+
+ n = ngx_atoi(host, last - host);
+
+ if (n != NGX_ERROR) {
+
+ if (n < 1 || n > 65535) {
+ u->err = "invalid port";
+ return NGX_ERROR;
+ }
+
+ u->port = (in_port_t) n;
+ sin->sin_port = htons((in_port_t) n);
+
+ u->port_text.len = last - host;
+ u->port_text.data = host;
+
+ u->wildcard = 1;
+
+ return NGX_OK;
+ }
+ }
+ }
+
+ u->no_port = 1;
+ u->port = u->default_port;
+ sin->sin_port = htons(u->default_port);
+ }
+
+ len = last - host;
+
+ if (len == 0) {
+ u->err = "no host";
+ return NGX_ERROR;
+ }
+
+ u->host.len = len;
+ u->host.data = host;
+
+ if (u->listen && len == 1 && *host == '*') {
+ sin->sin_addr.s_addr = INADDR_ANY;
+ u->wildcard = 1;
+ return NGX_OK;
+ }
+
+ sin->sin_addr.s_addr = ngx_inet_addr(host, len);
+
+ if (sin->sin_addr.s_addr != INADDR_NONE) {
+
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ u->wildcard = 1;
+ }
+
+ u->naddrs = 1;
+
+ u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+ if (sin == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(sin, &u->sockaddr, sizeof(struct sockaddr_in));
+
+ u->addrs[0].sockaddr = (struct sockaddr *) sin;
+ u->addrs[0].socklen = sizeof(struct sockaddr_in);
+
+ p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
+ &u->host, u->port) - p;
+ u->addrs[0].name.data = p;
+
+ return NGX_OK;
+ }
+
+ if (u->no_resolve) {
+ return NGX_OK;
+ }
+
+ if (ngx_inet_resolve_host(pool, u) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ u->family = u->addrs[0].sockaddr->sa_family;
+ u->socklen = u->addrs[0].socklen;
+ ngx_memcpy(&u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen);
+
+ switch (u->family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) &u->sockaddr;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ u->wildcard = 1;
+ }
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) &u->sockaddr;
+
+ if (sin->sin_addr.s_addr == INADDR_ANY) {
+ u->wildcard = 1;
+ }
+
+ break;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u)
+{
+#if (NGX_HAVE_INET6)
+ u_char *p, *host, *port, *last, *uri;
+ size_t len;
+ ngx_int_t n;
+ struct sockaddr_in6 *sin6;
+
+ u->socklen = sizeof(struct sockaddr_in6);
+ sin6 = (struct sockaddr_in6 *) &u->sockaddr;
+ sin6->sin6_family = AF_INET6;
+
+ host = u->url.data + 1;
+
+ last = u->url.data + u->url.len;
+
+ p = ngx_strlchr(host, last, ']');
+
+ if (p == NULL) {
+ u->err = "invalid host";
+ return NGX_ERROR;
+ }
+
+ port = p + 1;
+
+ uri = ngx_strlchr(port, last, '/');
+
+ if (uri) {
+ if (u->listen || !u->uri_part) {
+ u->err = "invalid host";
+ return NGX_ERROR;
+ }
+
+ u->uri.len = last - uri;
+ u->uri.data = uri;
+
+ last = uri;
+ }
+
+ if (port < last) {
+ if (*port != ':') {
+ u->err = "invalid host";
+ return NGX_ERROR;
+ }
+
+ port++;
+
+ len = last - port;
+
+ n = ngx_atoi(port, len);
+
+ if (n < 1 || n > 65535) {
+ u->err = "invalid port";
+ return NGX_ERROR;
+ }
+
+ u->port = (in_port_t) n;
+ sin6->sin6_port = htons((in_port_t) n);
+
+ u->port_text.len = len;
+ u->port_text.data = port;
+
+ } else {
+ u->no_port = 1;
+ u->port = u->default_port;
+ sin6->sin6_port = htons(u->default_port);
+ }
+
+ len = p - host;
+
+ if (len == 0) {
+ u->err = "no host";
+ return NGX_ERROR;
+ }
+
+ u->host.len = len + 2;
+ u->host.data = host - 1;
+
+ if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) {
+ u->err = "invalid IPv6 address";
+ return NGX_ERROR;
+ }
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+ u->wildcard = 1;
+ }
+
+ u->family = AF_INET6;
+ u->naddrs = 1;
+
+ u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin6 = ngx_pcalloc(pool, sizeof(struct sockaddr_in6));
+ if (sin6 == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(sin6, &u->sockaddr, sizeof(struct sockaddr_in6));
+
+ u->addrs[0].sockaddr = (struct sockaddr *) sin6;
+ u->addrs[0].socklen = sizeof(struct sockaddr_in6);
+
+ p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
+ &u->host, u->port) - p;
+ u->addrs[0].name.data = p;
+
+ return NGX_OK;
+
+#else
+
+ u->err = "the INET6 sockets are not supported on this platform";
+
+ return NGX_ERROR;
+
+#endif
+}
+
+
+#if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
+{
+ u_char *p, *host;
+ size_t len;
+ in_port_t port;
+ ngx_uint_t i;
+ struct addrinfo hints, *res, *rp;
+ struct sockaddr_in *sin;
+ struct sockaddr_in6 *sin6;
+
+ port = htons(u->port);
+
+ host = ngx_alloc(u->host.len + 1, pool->log);
+ if (host == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
+ ngx_memzero(&hints, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags = AI_ADDRCONFIG;
+#endif
+
+ if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) {
+ u->err = "host not found";
+ ngx_free(host);
+ return NGX_ERROR;
+ }
+
+ ngx_free(host);
+
+ for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) {
+
+ switch (rp->ai_family) {
+
+ case AF_INET:
+ case AF_INET6:
+ break;
+
+ default:
+ continue;
+ }
+
+ i++;
+ }
+
+ if (i == 0) {
+ u->err = "host not found";
+ goto failed;
+ }
+
+ /* MP: ngx_shared_palloc() */
+
+ u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ goto failed;
+ }
+
+ u->naddrs = i;
+
+ i = 0;
+
+ /* AF_INET addresses first */
+
+ for (rp = res; rp != NULL; rp = rp->ai_next) {
+
+ if (rp->ai_family != AF_INET) {
+ continue;
+ }
+
+ sin = ngx_pcalloc(pool, rp->ai_addrlen);
+ if (sin == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen);
+
+ sin->sin_port = port;
+
+ u->addrs[i].sockaddr = (struct sockaddr *) sin;
+ u->addrs[i].socklen = rp->ai_addrlen;
+
+ len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+
+ p = ngx_pnalloc(pool, len);
+ if (p == NULL) {
+ goto failed;
+ }
+
+ len = ngx_sock_ntop((struct sockaddr *) sin, rp->ai_addrlen, p, len, 1);
+
+ u->addrs[i].name.len = len;
+ u->addrs[i].name.data = p;
+
+ i++;
+ }
+
+ for (rp = res; rp != NULL; rp = rp->ai_next) {
+
+ if (rp->ai_family != AF_INET6) {
+ continue;
+ }
+
+ sin6 = ngx_pcalloc(pool, rp->ai_addrlen);
+ if (sin6 == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen);
+
+ sin6->sin6_port = port;
+
+ u->addrs[i].sockaddr = (struct sockaddr *) sin6;
+ u->addrs[i].socklen = rp->ai_addrlen;
+
+ len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1;
+
+ p = ngx_pnalloc(pool, len);
+ if (p == NULL) {
+ goto failed;
+ }
+
+ len = ngx_sock_ntop((struct sockaddr *) sin6, rp->ai_addrlen, p,
+ len, 1);
+
+ u->addrs[i].name.len = len;
+ u->addrs[i].name.data = p;
+
+ i++;
+ }
+
+ freeaddrinfo(res);
+ return NGX_OK;
+
+failed:
+
+ freeaddrinfo(res);
+ return NGX_ERROR;
+}
+
+#else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */
+
+ngx_int_t
+ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u)
+{
+ u_char *p, *host;
+ size_t len;
+ in_port_t port;
+ in_addr_t in_addr;
+ ngx_uint_t i;
+ struct hostent *h;
+ struct sockaddr_in *sin;
+
+ /* AF_INET only */
+
+ port = htons(u->port);
+
+ in_addr = ngx_inet_addr(u->host.data, u->host.len);
+
+ if (in_addr == INADDR_NONE) {
+ host = ngx_alloc(u->host.len + 1, pool->log);
+ if (host == NULL) {
+ return NGX_ERROR;
+ }
+
+ (void) ngx_cpystrn(host, u->host.data, u->host.len + 1);
+
+ h = gethostbyname((char *) host);
+
+ ngx_free(host);
+
+ if (h == NULL || h->h_addr_list[0] == NULL) {
+ u->err = "host not found";
+ return NGX_ERROR;
+ }
+
+ for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
+
+ /* MP: ngx_shared_palloc() */
+
+ u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->naddrs = i;
+
+ for (i = 0; i < u->naddrs; i++) {
+
+ sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+ if (sin == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = port;
+ sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
+
+ u->addrs[i].sockaddr = (struct sockaddr *) sin;
+ u->addrs[i].socklen = sizeof(struct sockaddr_in);
+
+ len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
+
+ p = ngx_pnalloc(pool, len);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ len = ngx_sock_ntop((struct sockaddr *) sin,
+ sizeof(struct sockaddr_in), p, len, 1);
+
+ u->addrs[i].name.len = len;
+ u->addrs[i].name.data = p;
+ }
+
+ } else {
+
+ /* MP: ngx_shared_palloc() */
+
+ u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t));
+ if (u->addrs == NULL) {
+ return NGX_ERROR;
+ }
+
+ sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in));
+ if (sin == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->naddrs = 1;
+
+ sin->sin_family = AF_INET;
+ sin->sin_port = port;
+ sin->sin_addr.s_addr = in_addr;
+
+ u->addrs[0].sockaddr = (struct sockaddr *) sin;
+ u->addrs[0].socklen = sizeof(struct sockaddr_in);
+
+ p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ u->addrs[0].name.len = ngx_sprintf(p, "%V:%d",
+ &u->host, ntohs(port)) - p;
+ u->addrs[0].name.data = p;
+ }
+
+ return NGX_OK;
+}
+
+#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */
+
+
+ngx_int_t
+ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
+ struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port)
+{
+ struct sockaddr_in *sin1, *sin2;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin61, *sin62;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ size_t len;
+ struct sockaddr_un *saun1, *saun2;
+#endif
+
+ if (sa1->sa_family != sa2->sa_family) {
+ return NGX_DECLINED;
+ }
+
+ switch (sa1->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+
+ sin61 = (struct sockaddr_in6 *) sa1;
+ sin62 = (struct sockaddr_in6 *) sa2;
+
+ if (cmp_port && sin61->sin6_port != sin62->sin6_port) {
+ return NGX_DECLINED;
+ }
+
+ if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) {
+ return NGX_DECLINED;
+ }
+
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+
+ saun1 = (struct sockaddr_un *) sa1;
+ saun2 = (struct sockaddr_un *) sa2;
+
+ if (slen1 < slen2) {
+ len = slen1 - offsetof(struct sockaddr_un, sun_path);
+
+ } else {
+ len = slen2 - offsetof(struct sockaddr_un, sun_path);
+ }
+
+ if (len > sizeof(saun1->sun_path)) {
+ len = sizeof(saun1->sun_path);
+ }
+
+ if (ngx_memcmp(&saun1->sun_path, &saun2->sun_path, len) != 0) {
+ return NGX_DECLINED;
+ }
+
+ break;
+#endif
+
+ default: /* AF_INET */
+
+ sin1 = (struct sockaddr_in *) sa1;
+ sin2 = (struct sockaddr_in *) sa2;
+
+ if (cmp_port && sin1->sin_port != sin2->sin_port) {
+ return NGX_DECLINED;
+ }
+
+ if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) {
+ return NGX_DECLINED;
+ }
+
+ break;
+ }
+
+ return NGX_OK;
+}
+
+
+in_port_t
+ngx_inet_get_port(struct sockaddr *sa)
+{
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (sa->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) sa;
+ return ntohs(sin6->sin6_port);
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ return 0;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) sa;
+ return ntohs(sin->sin_port);
+ }
+}
+
+
+void
+ngx_inet_set_port(struct sockaddr *sa, in_port_t port)
+{
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (sa->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) sa;
+ sin6->sin6_port = htons(port);
+ break;
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+ case AF_UNIX:
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) sa;
+ sin->sin_port = htons(port);
+ break;
+ }
+}
diff --git a/app/nginx/src/core/ngx_inet.h b/app/nginx/src/core/ngx_inet.h
new file mode 100644
index 0000000..538771e
--- /dev/null
+++ b/app/nginx/src/core/ngx_inet.h
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_INET_H_INCLUDED_
+#define _NGX_INET_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1)
+#define NGX_INET6_ADDRSTRLEN \
+ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1)
+#define NGX_UNIX_ADDRSTRLEN \
+ (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+#define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN)
+#elif (NGX_HAVE_INET6)
+#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1)
+#else
+#define NGX_SOCKADDR_STRLEN (NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1)
+#endif
+
+/* compatibility */
+#define NGX_SOCKADDRLEN sizeof(ngx_sockaddr_t)
+
+
+typedef union {
+ struct sockaddr sockaddr;
+ struct sockaddr_in sockaddr_in;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 sockaddr_in6;
+#endif
+#if (NGX_HAVE_UNIX_DOMAIN)
+ struct sockaddr_un sockaddr_un;
+#endif
+} ngx_sockaddr_t;
+
+
+typedef struct {
+ in_addr_t addr;
+ in_addr_t mask;
+} ngx_in_cidr_t;
+
+
+#if (NGX_HAVE_INET6)
+
+typedef struct {
+ struct in6_addr addr;
+ struct in6_addr mask;
+} ngx_in6_cidr_t;
+
+#endif
+
+
+typedef struct {
+ ngx_uint_t family;
+ union {
+ ngx_in_cidr_t in;
+#if (NGX_HAVE_INET6)
+ ngx_in6_cidr_t in6;
+#endif
+ } u;
+} ngx_cidr_t;
+
+
+typedef struct {
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t name;
+} ngx_addr_t;
+
+
+typedef struct {
+ ngx_str_t url;
+ ngx_str_t host;
+ ngx_str_t port_text;
+ ngx_str_t uri;
+
+ in_port_t port;
+ in_port_t default_port;
+ int family;
+
+ unsigned listen:1;
+ unsigned uri_part:1;
+ unsigned no_resolve:1;
+
+ unsigned no_port:1;
+ unsigned wildcard:1;
+
+ socklen_t socklen;
+ ngx_sockaddr_t sockaddr;
+
+ ngx_addr_t *addrs;
+ ngx_uint_t naddrs;
+
+ char *err;
+} ngx_url_t;
+
+
+in_addr_t ngx_inet_addr(u_char *text, size_t len);
+#if (NGX_HAVE_INET6)
+ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr);
+size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len);
+#endif
+size_t ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text,
+ size_t len, ngx_uint_t port);
+size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len);
+ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr);
+ngx_int_t ngx_cidr_match(struct sockaddr *sa, ngx_array_t *cidrs);
+ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text,
+ size_t len);
+ngx_int_t ngx_parse_addr_port(ngx_pool_t *pool, ngx_addr_t *addr,
+ u_char *text, size_t len);
+ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u);
+ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u);
+ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, socklen_t slen1,
+ struct sockaddr *sa2, socklen_t slen2, ngx_uint_t cmp_port);
+in_port_t ngx_inet_get_port(struct sockaddr *sa);
+void ngx_inet_set_port(struct sockaddr *sa, in_port_t port);
+
+
+#endif /* _NGX_INET_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_list.c b/app/nginx/src/core/ngx_list.c
new file mode 100644
index 0000000..d0eb159
--- /dev/null
+++ b/app/nginx/src/core/ngx_list.c
@@ -0,0 +1,63 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ngx_list_t *
+ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size)
+{
+ ngx_list_t *list;
+
+ list = ngx_palloc(pool, sizeof(ngx_list_t));
+ if (list == NULL) {
+ return NULL;
+ }
+
+ if (ngx_list_init(list, pool, n, size) != NGX_OK) {
+ return NULL;
+ }
+
+ return list;
+}
+
+
+void *
+ngx_list_push(ngx_list_t *l)
+{
+ void *elt;
+ ngx_list_part_t *last;
+
+ last = l->last;
+
+ if (last->nelts == l->nalloc) {
+
+ /* the last part is full, allocate a new list part */
+
+ last = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
+ if (last == NULL) {
+ return NULL;
+ }
+
+ last->elts = ngx_palloc(l->pool, l->nalloc * l->size);
+ if (last->elts == NULL) {
+ return NULL;
+ }
+
+ last->nelts = 0;
+ last->next = NULL;
+
+ l->last->next = last;
+ l->last = last;
+ }
+
+ elt = (char *) last->elts + l->size * last->nelts;
+ last->nelts++;
+
+ return elt;
+}
diff --git a/app/nginx/src/core/ngx_list.h b/app/nginx/src/core/ngx_list.h
new file mode 100644
index 0000000..e0fe643
--- /dev/null
+++ b/app/nginx/src/core/ngx_list.h
@@ -0,0 +1,83 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_LIST_H_INCLUDED_
+#define _NGX_LIST_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct ngx_list_part_s ngx_list_part_t;
+
+struct ngx_list_part_s {
+ void *elts;
+ ngx_uint_t nelts;
+ ngx_list_part_t *next;
+};
+
+
+typedef struct {
+ ngx_list_part_t *last;
+ ngx_list_part_t part;
+ size_t size;
+ ngx_uint_t nalloc;
+ ngx_pool_t *pool;
+} ngx_list_t;
+
+
+ngx_list_t *ngx_list_create(ngx_pool_t *pool, ngx_uint_t n, size_t size);
+
+static ngx_inline ngx_int_t
+ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, size_t size)
+{
+ list->part.elts = ngx_palloc(pool, n * size);
+ if (list->part.elts == NULL) {
+ return NGX_ERROR;
+ }
+
+ list->part.nelts = 0;
+ list->part.next = NULL;
+ list->last = &list->part;
+ list->size = size;
+ list->nalloc = n;
+ list->pool = pool;
+
+ return NGX_OK;
+}
+
+
+/*
+ *
+ * the iteration through the list:
+ *
+ * part = &list.part;
+ * data = part->elts;
+ *
+ * for (i = 0 ;; i++) {
+ *
+ * if (i >= part->nelts) {
+ * if (part->next == NULL) {
+ * break;
+ * }
+ *
+ * part = part->next;
+ * data = part->elts;
+ * i = 0;
+ * }
+ *
+ * ... data[i] ...
+ *
+ * }
+ */
+
+
+void *ngx_list_push(ngx_list_t *list);
+
+
+#endif /* _NGX_LIST_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_log.c b/app/nginx/src/core/ngx_log.c
new file mode 100644
index 0000000..8e9408d
--- /dev/null
+++ b/app/nginx/src/core/ngx_log.c
@@ -0,0 +1,755 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+static char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log);
+static void ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log);
+
+
+#if (NGX_DEBUG)
+
+static void ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level,
+ u_char *buf, size_t len);
+static void ngx_log_memory_cleanup(void *data);
+
+
+typedef struct {
+ u_char *start;
+ u_char *end;
+ u_char *pos;
+ ngx_atomic_t written;
+} ngx_log_memory_buf_t;
+
+#endif
+
+
+static ngx_command_t ngx_errlog_commands[] = {
+
+ { ngx_string("error_log"),
+ NGX_MAIN_CONF|NGX_CONF_1MORE,
+ ngx_error_log,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_errlog_module_ctx = {
+ ngx_string("errlog"),
+ NULL,
+ NULL
+};
+
+
+ngx_module_t ngx_errlog_module = {
+ NGX_MODULE_V1,
+ &ngx_errlog_module_ctx, /* module context */
+ ngx_errlog_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_log_t ngx_log;
+static ngx_open_file_t ngx_log_file;
+ngx_uint_t ngx_use_stderr = 1;
+
+
+static ngx_str_t err_levels[] = {
+ ngx_null_string,
+ ngx_string("emerg"),
+ ngx_string("alert"),
+ ngx_string("crit"),
+ ngx_string("error"),
+ ngx_string("warn"),
+ ngx_string("notice"),
+ ngx_string("info"),
+ ngx_string("debug")
+};
+
+static const char *debug_levels[] = {
+ "debug_core", "debug_alloc", "debug_mutex", "debug_event",
+ "debug_http", "debug_mail", "debug_stream"
+};
+
+
+#if (NGX_HAVE_VARIADIC_MACROS)
+
+void
+ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...)
+
+#else
+
+void
+ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, va_list args)
+
+#endif
+{
+#if (NGX_HAVE_VARIADIC_MACROS)
+ va_list args;
+#endif
+ u_char *p, *last, *msg;
+ ssize_t n;
+ ngx_uint_t wrote_stderr, debug_connection;
+ u_char errstr[NGX_MAX_ERROR_STR];
+
+ last = errstr + NGX_MAX_ERROR_STR;
+
+ p = ngx_cpymem(errstr, ngx_cached_err_log_time.data,
+ ngx_cached_err_log_time.len);
+
+ p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]);
+
+ /* pid#tid */
+ p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ",
+ ngx_log_pid, ngx_log_tid);
+
+ if (log->connection) {
+ p = ngx_slprintf(p, last, "*%uA ", log->connection);
+ }
+
+ msg = p;
+
+#if (NGX_HAVE_VARIADIC_MACROS)
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(p, last, fmt, args);
+ va_end(args);
+
+#else
+
+ p = ngx_vslprintf(p, last, fmt, args);
+
+#endif
+
+ if (err) {
+ p = ngx_log_errno(p, last, err);
+ }
+
+ if (level != NGX_LOG_DEBUG && log->handler) {
+ p = log->handler(log, p, last - p);
+ }
+
+ if (p > last - NGX_LINEFEED_SIZE) {
+ p = last - NGX_LINEFEED_SIZE;
+ }
+
+ ngx_linefeed(p);
+
+ wrote_stderr = 0;
+ debug_connection = (log->log_level & NGX_LOG_DEBUG_CONNECTION) != 0;
+
+ while (log) {
+
+ if (log->log_level < level && !debug_connection) {
+ break;
+ }
+
+ if (log->writer) {
+ log->writer(log, level, errstr, p - errstr);
+ goto next;
+ }
+
+ if (ngx_time() == log->disk_full_time) {
+
+ /*
+ * on FreeBSD writing to a full filesystem with enabled softupdates
+ * may block process for much longer time than writing to non-full
+ * filesystem, so we skip writing to a log for one second
+ */
+
+ goto next;
+ }
+
+ n = ngx_write_fd(log->file->fd, errstr, p - errstr);
+
+ if (n == -1 && ngx_errno == NGX_ENOSPC) {
+ log->disk_full_time = ngx_time();
+ }
+
+ if (log->file->fd == ngx_stderr) {
+ wrote_stderr = 1;
+ }
+
+ next:
+
+ log = log->next;
+ }
+
+ if (!ngx_use_stderr
+ || level > NGX_LOG_WARN
+ || wrote_stderr)
+ {
+ return;
+ }
+
+ msg -= (7 + err_levels[level].len + 3);
+
+ (void) ngx_sprintf(msg, "nginx: [%V] ", &err_levels[level]);
+
+ (void) ngx_write_console(ngx_stderr, msg, p - msg);
+}
+
+
+#if !(NGX_HAVE_VARIADIC_MACROS)
+
+void ngx_cdecl
+ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...)
+{
+ va_list args;
+
+ if (log->log_level >= level) {
+ va_start(args, fmt);
+ ngx_log_error_core(level, log, err, fmt, args);
+ va_end(args);
+ }
+}
+
+
+void ngx_cdecl
+ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, args);
+ va_end(args);
+}
+
+#endif
+
+
+void ngx_cdecl
+ngx_log_abort(ngx_err_t err, const char *fmt, ...)
+{
+ u_char *p;
+ va_list args;
+ u_char errstr[NGX_MAX_CONF_ERRSTR];
+
+ va_start(args, fmt);
+ p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args);
+ va_end(args);
+
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+ "%*s", p - errstr, errstr);
+}
+
+
+void ngx_cdecl
+ngx_log_stderr(ngx_err_t err, const char *fmt, ...)
+{
+ u_char *p, *last;
+ va_list args;
+ u_char errstr[NGX_MAX_ERROR_STR];
+
+ last = errstr + NGX_MAX_ERROR_STR;
+
+ p = ngx_cpymem(errstr, "nginx: ", 7);
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(p, last, fmt, args);
+ va_end(args);
+
+ if (err) {
+ p = ngx_log_errno(p, last, err);
+ }
+
+ if (p > last - NGX_LINEFEED_SIZE) {
+ p = last - NGX_LINEFEED_SIZE;
+ }
+
+ ngx_linefeed(p);
+
+ (void) ngx_write_console(ngx_stderr, errstr, p - errstr);
+}
+
+
+u_char *
+ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err)
+{
+ if (buf > last - 50) {
+
+ /* leave a space for an error code */
+
+ buf = last - 50;
+ *buf++ = '.';
+ *buf++ = '.';
+ *buf++ = '.';
+ }
+
+#if (NGX_WIN32)
+ buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000)
+ ? " (%d: " : " (%Xd: ", err);
+#else
+ buf = ngx_slprintf(buf, last, " (%d: ", err);
+#endif
+
+ buf = ngx_strerror(err, buf, last - buf);
+
+ if (buf < last) {
+ *buf++ = ')';
+ }
+
+ return buf;
+}
+
+
+ngx_log_t *
+ngx_log_init(u_char *prefix)
+{
+ u_char *p, *name;
+ size_t nlen, plen;
+
+ ngx_log.file = &ngx_log_file;
+ ngx_log.log_level = NGX_LOG_NOTICE;
+
+ name = (u_char *) NGX_ERROR_LOG_PATH;
+
+ /*
+ * we use ngx_strlen() here since BCC warns about
+ * condition is always false and unreachable code
+ */
+
+ nlen = ngx_strlen(name);
+
+ if (nlen == 0) {
+ ngx_log_file.fd = ngx_stderr;
+ return &ngx_log;
+ }
+
+ p = NULL;
+
+#if (NGX_WIN32)
+ if (name[1] != ':') {
+#else
+ if (name[0] != '/') {
+#endif
+
+ if (prefix) {
+ plen = ngx_strlen(prefix);
+
+ } else {
+#ifdef NGX_PREFIX
+ prefix = (u_char *) NGX_PREFIX;
+ plen = ngx_strlen(prefix);
+#else
+ plen = 0;
+#endif
+ }
+
+ if (plen) {
+ name = malloc(plen + nlen + 2);
+ if (name == NULL) {
+ return NULL;
+ }
+
+ p = ngx_cpymem(name, prefix, plen);
+
+ if (!ngx_path_separator(*(p - 1))) {
+ *p++ = '/';
+ }
+
+ ngx_cpystrn(p, (u_char *) NGX_ERROR_LOG_PATH, nlen + 1);
+
+ p = name;
+ }
+ }
+
+ ngx_log_file.fd = ngx_open_file(name, NGX_FILE_APPEND,
+ NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS);
+
+ if (ngx_log_file.fd == NGX_INVALID_FILE) {
+ ngx_log_stderr(ngx_errno,
+ "[alert] could not open error log file: "
+ ngx_open_file_n " \"%s\" failed", name);
+#if (NGX_WIN32)
+ ngx_event_log(ngx_errno,
+ "could not open error log file: "
+ ngx_open_file_n " \"%s\" failed", name);
+#endif
+
+ ngx_log_file.fd = ngx_stderr;
+ }
+
+ if (p) {
+ ngx_free(p);
+ }
+
+ return &ngx_log;
+}
+
+
+ngx_int_t
+ngx_log_open_default(ngx_cycle_t *cycle)
+{
+ ngx_log_t *log;
+ static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
+
+ if (ngx_log_get_file_log(&cycle->new_log) != NULL) {
+ return NGX_OK;
+ }
+
+ if (cycle->new_log.log_level != 0) {
+ /* there are some error logs, but no files */
+
+ log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
+ if (log == NULL) {
+ return NGX_ERROR;
+ }
+
+ } else {
+ /* no error logs at all */
+ log = &cycle->new_log;
+ }
+
+ log->log_level = NGX_LOG_ERR;
+
+ log->file = ngx_conf_open_file(cycle, &error_log);
+ if (log->file == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (log != &cycle->new_log) {
+ ngx_log_insert(&cycle->new_log, log);
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_log_redirect_stderr(ngx_cycle_t *cycle)
+{
+ ngx_fd_t fd;
+
+ if (cycle->log_use_stderr) {
+ return NGX_OK;
+ }
+
+ /* file log always exists when we are called */
+ fd = ngx_log_get_file_log(cycle->log)->file->fd;
+
+ if (fd != ngx_stderr) {
+ if (ngx_set_stderr(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ ngx_set_stderr_n " failed");
+
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_log_t *
+ngx_log_get_file_log(ngx_log_t *head)
+{
+ ngx_log_t *log;
+
+ for (log = head; log; log = log->next) {
+ if (log->file != NULL) {
+ return log;
+ }
+ }
+
+ return NULL;
+}
+
+
+static char *
+ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
+{
+ ngx_uint_t i, n, d, found;
+ ngx_str_t *value;
+
+ if (cf->args->nelts == 2) {
+ log->log_level = NGX_LOG_ERR;
+ return NGX_CONF_OK;
+ }
+
+ value = cf->args->elts;
+
+ for (i = 2; i < cf->args->nelts; i++) {
+ found = 0;
+
+ for (n = 1; n <= NGX_LOG_DEBUG; n++) {
+ if (ngx_strcmp(value[i].data, err_levels[n].data) == 0) {
+
+ if (log->log_level != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate log level \"%V\"",
+ &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ log->log_level = n;
+ found = 1;
+ break;
+ }
+ }
+
+ for (n = 0, d = NGX_LOG_DEBUG_FIRST; d <= NGX_LOG_DEBUG_LAST; d <<= 1) {
+ if (ngx_strcmp(value[i].data, debug_levels[n++]) == 0) {
+ if (log->log_level & ~NGX_LOG_DEBUG_ALL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid log level \"%V\"",
+ &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ log->log_level |= d;
+ found = 1;
+ break;
+ }
+ }
+
+
+ if (!found) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid log level \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ if (log->log_level == NGX_LOG_DEBUG) {
+ log->log_level = NGX_LOG_DEBUG_ALL;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_log_t *dummy;
+
+ dummy = &cf->cycle->new_log;
+
+ return ngx_log_set_log(cf, &dummy);
+}
+
+
+char *
+ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
+{
+ ngx_log_t *new_log;
+ ngx_str_t *value, name;
+ ngx_syslog_peer_t *peer;
+
+ if (*head != NULL && (*head)->log_level == 0) {
+ new_log = *head;
+
+ } else {
+
+ new_log = ngx_pcalloc(cf->pool, sizeof(ngx_log_t));
+ if (new_log == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (*head == NULL) {
+ *head = new_log;
+ }
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "stderr") == 0) {
+ ngx_str_null(&name);
+ cf->cycle->log_use_stderr = 1;
+
+ new_log->file = ngx_conf_open_file(cf->cycle, &name);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else if (ngx_strncmp(value[1].data, "memory:", 7) == 0) {
+
+#if (NGX_DEBUG)
+ size_t size, needed;
+ ngx_pool_cleanup_t *cln;
+ ngx_log_memory_buf_t *buf;
+
+ value[1].len -= 7;
+ value[1].data += 7;
+
+ needed = sizeof("MEMLOG :" NGX_LINEFEED)
+ + cf->conf_file->file.name.len
+ + NGX_SIZE_T_LEN
+ + NGX_INT_T_LEN
+ + NGX_MAX_ERROR_STR;
+
+ size = ngx_parse_size(&value[1]);
+
+ if (size == (size_t) NGX_ERROR || size < needed) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid buffer size \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ buf = ngx_pcalloc(cf->pool, sizeof(ngx_log_memory_buf_t));
+ if (buf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ buf->start = ngx_pnalloc(cf->pool, size);
+ if (buf->start == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ buf->end = buf->start + size;
+
+ buf->pos = ngx_slprintf(buf->start, buf->end, "MEMLOG %uz %V:%ui%N",
+ size, &cf->conf_file->file.name,
+ cf->conf_file->line);
+
+ ngx_memset(buf->pos, ' ', buf->end - buf->pos);
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ cln->data = new_log;
+ cln->handler = ngx_log_memory_cleanup;
+
+ new_log->writer = ngx_log_memory_writer;
+ new_log->wdata = buf;
+
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "nginx was built without debug support");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
+ if (peer == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ new_log->writer = ngx_syslog_writer;
+ new_log->wdata = peer;
+
+ } else {
+ new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (*head != new_log) {
+ ngx_log_insert(*head, new_log);
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static void
+ngx_log_insert(ngx_log_t *log, ngx_log_t *new_log)
+{
+ ngx_log_t tmp;
+
+ if (new_log->log_level > log->log_level) {
+
+ /*
+ * list head address is permanent, insert new log after
+ * head and swap its contents with head
+ */
+
+ tmp = *log;
+ *log = *new_log;
+ *new_log = tmp;
+
+ log->next = new_log;
+ return;
+ }
+
+ while (log->next) {
+ if (new_log->log_level > log->next->log_level) {
+ new_log->next = log->next;
+ log->next = new_log;
+ return;
+ }
+
+ log = log->next;
+ }
+
+ log->next = new_log;
+}
+
+
+#if (NGX_DEBUG)
+
+static void
+ngx_log_memory_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len)
+{
+ u_char *p;
+ size_t avail, written;
+ ngx_log_memory_buf_t *mem;
+
+ mem = log->wdata;
+
+ if (mem == NULL) {
+ return;
+ }
+
+ written = ngx_atomic_fetch_add(&mem->written, len);
+
+ p = mem->pos + written % (mem->end - mem->pos);
+
+ avail = mem->end - p;
+
+ if (avail >= len) {
+ ngx_memcpy(p, buf, len);
+
+ } else {
+ ngx_memcpy(p, buf, avail);
+ ngx_memcpy(mem->pos, buf + avail, len - avail);
+ }
+}
+
+
+static void
+ngx_log_memory_cleanup(void *data)
+{
+ ngx_log_t *log = data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "destroy memory log buffer");
+
+ log->wdata = NULL;
+}
+
+#endif
diff --git a/app/nginx/src/core/ngx_log.h b/app/nginx/src/core/ngx_log.h
new file mode 100644
index 0000000..afb73bf
--- /dev/null
+++ b/app/nginx/src/core/ngx_log.h
@@ -0,0 +1,268 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_LOG_H_INCLUDED_
+#define _NGX_LOG_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_LOG_STDERR 0
+#define NGX_LOG_EMERG 1
+#define NGX_LOG_ALERT 2
+#define NGX_LOG_CRIT 3
+#define NGX_LOG_ERR 4
+#define NGX_LOG_WARN 5
+#define NGX_LOG_NOTICE 6
+#define NGX_LOG_INFO 7
+#define NGX_LOG_DEBUG 8
+
+#define NGX_LOG_DEBUG_CORE 0x010
+#define NGX_LOG_DEBUG_ALLOC 0x020
+#define NGX_LOG_DEBUG_MUTEX 0x040
+#define NGX_LOG_DEBUG_EVENT 0x080
+#define NGX_LOG_DEBUG_HTTP 0x100
+#define NGX_LOG_DEBUG_MAIL 0x200
+#define NGX_LOG_DEBUG_STREAM 0x400
+
+/*
+ * do not forget to update debug_levels[] in src/core/ngx_log.c
+ * after the adding a new debug level
+ */
+
+#define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
+#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_STREAM
+#define NGX_LOG_DEBUG_CONNECTION 0x80000000
+#define NGX_LOG_DEBUG_ALL 0x7ffffff0
+
+
+typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len);
+typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level,
+ u_char *buf, size_t len);
+
+
+struct ngx_log_s {
+ ngx_uint_t log_level;
+ ngx_open_file_t *file;
+
+ ngx_atomic_uint_t connection;
+
+ time_t disk_full_time;
+
+ ngx_log_handler_pt handler;
+ void *data;
+
+ ngx_log_writer_pt writer;
+ void *wdata;
+
+ /*
+ * we declare "action" as "char *" because the actions are usually
+ * the static strings and in the "u_char *" case we have to override
+ * their types all the time
+ */
+
+ char *action;
+
+ ngx_log_t *next;
+};
+
+
+#define NGX_MAX_ERROR_STR 2048
+
+
+/*********************************/
+
+#if (NGX_HAVE_C99_VARIADIC_MACROS)
+
+#define NGX_HAVE_VARIADIC_MACROS 1
+
+#define ngx_log_error(level, log, ...) \
+ if ((log)->log_level >= level) ngx_log_error_core(level, log, __VA_ARGS__)
+
+void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...);
+
+#define ngx_log_debug(level, log, ...) \
+ if ((log)->log_level & level) \
+ ngx_log_error_core(NGX_LOG_DEBUG, log, __VA_ARGS__)
+
+/*********************************/
+
+#elif (NGX_HAVE_GCC_VARIADIC_MACROS)
+
+#define NGX_HAVE_VARIADIC_MACROS 1
+
+#define ngx_log_error(level, log, args...) \
+ if ((log)->log_level >= level) ngx_log_error_core(level, log, args)
+
+void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...);
+
+#define ngx_log_debug(level, log, args...) \
+ if ((log)->log_level & level) \
+ ngx_log_error_core(NGX_LOG_DEBUG, log, args)
+
+/*********************************/
+
+#else /* no variadic macros */
+
+#define NGX_HAVE_VARIADIC_MACROS 0
+
+void ngx_cdecl ngx_log_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...);
+void ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
+ const char *fmt, va_list args);
+void ngx_cdecl ngx_log_debug_core(ngx_log_t *log, ngx_err_t err,
+ const char *fmt, ...);
+
+
+#endif /* variadic macros */
+
+
+/*********************************/
+
+#if (NGX_DEBUG)
+
+#if (NGX_HAVE_VARIADIC_MACROS)
+
+#define ngx_log_debug0(level, log, err, fmt) \
+ ngx_log_debug(level, log, err, fmt)
+
+#define ngx_log_debug1(level, log, err, fmt, arg1) \
+ ngx_log_debug(level, log, err, fmt, arg1)
+
+#define ngx_log_debug2(level, log, err, fmt, arg1, arg2) \
+ ngx_log_debug(level, log, err, fmt, arg1, arg2)
+
+#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \
+ ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3)
+
+#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4) \
+ ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3, arg4)
+
+#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5) \
+ ngx_log_debug(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5)
+
+#define ngx_log_debug6(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6) \
+ ngx_log_debug(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6)
+
+#define ngx_log_debug7(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
+ ngx_log_debug(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+
+#define ngx_log_debug8(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
+ ngx_log_debug(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+
+
+#else /* no variadic macros */
+
+#define ngx_log_debug0(level, log, err, fmt) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt)
+
+#define ngx_log_debug1(level, log, err, fmt, arg1) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1)
+
+#define ngx_log_debug2(level, log, err, fmt, arg1, arg2) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1, arg2)
+
+#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3)
+
+#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4)
+
+#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5)
+
+#define ngx_log_debug6(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+
+#define ngx_log_debug7(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+
+#define ngx_log_debug8(level, log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
+ if ((log)->log_level & level) \
+ ngx_log_debug_core(log, err, fmt, \
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
+
+#endif
+
+#else /* !NGX_DEBUG */
+
+#define ngx_log_debug0(level, log, err, fmt)
+#define ngx_log_debug1(level, log, err, fmt, arg1)
+#define ngx_log_debug2(level, log, err, fmt, arg1, arg2)
+#define ngx_log_debug3(level, log, err, fmt, arg1, arg2, arg3)
+#define ngx_log_debug4(level, log, err, fmt, arg1, arg2, arg3, arg4)
+#define ngx_log_debug5(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5)
+#define ngx_log_debug6(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
+#define ngx_log_debug7(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7)
+#define ngx_log_debug8(level, log, err, fmt, arg1, arg2, arg3, arg4, arg5, \
+ arg6, arg7, arg8)
+
+#endif
+
+/*********************************/
+
+ngx_log_t *ngx_log_init(u_char *prefix);
+void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...);
+void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
+u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
+ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle);
+ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle);
+ngx_log_t *ngx_log_get_file_log(ngx_log_t *head);
+char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head);
+
+
+/*
+ * ngx_write_stderr() cannot be implemented as macro, since
+ * MSVC does not allow to use #ifdef inside macro parameters.
+ *
+ * ngx_write_fd() is used instead of ngx_write_console(), since
+ * CharToOemBuff() inside ngx_write_console() cannot be used with
+ * read only buffer as destination and CharToOemBuff() is not needed
+ * for ngx_write_stderr() anyway.
+ */
+static ngx_inline void
+ngx_write_stderr(char *text)
+{
+ (void) ngx_write_fd(ngx_stderr, text, ngx_strlen(text));
+}
+
+
+static ngx_inline void
+ngx_write_stdout(char *text)
+{
+ (void) ngx_write_fd(ngx_stdout, text, ngx_strlen(text));
+}
+
+
+extern ngx_module_t ngx_errlog_module;
+extern ngx_uint_t ngx_use_stderr;
+
+
+#endif /* _NGX_LOG_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_md5.c b/app/nginx/src/core/ngx_md5.c
new file mode 100644
index 0000000..c25d002
--- /dev/null
+++ b/app/nginx/src/core/ngx_md5.c
@@ -0,0 +1,283 @@
+
+/*
+ * An internal implementation, based on Alexander Peslyak's
+ * public domain implementation:
+ * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_md5.h>
+
+
+static const u_char *ngx_md5_body(ngx_md5_t *ctx, const u_char *data,
+ size_t size);
+
+
+void
+ngx_md5_init(ngx_md5_t *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->bytes = 0;
+}
+
+
+void
+ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+ ctx->bytes += size;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ ngx_memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ ngx_memcpy(&ctx->buffer[used], data, free);
+ data = (u_char *) data + free;
+ size -= free;
+ (void) ngx_md5_body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = ngx_md5_body(ctx, data, size & ~(size_t) 0x3f);
+ size &= 0x3f;
+ }
+
+ ngx_memcpy(ctx->buffer, data, size);
+}
+
+
+void
+ngx_md5_final(u_char result[16], ngx_md5_t *ctx)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ ngx_memzero(&ctx->buffer[used], free);
+ (void) ngx_md5_body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ ngx_memzero(&ctx->buffer[used], free - 8);
+
+ ctx->bytes <<= 3;
+ ctx->buffer[56] = (u_char) ctx->bytes;
+ ctx->buffer[57] = (u_char) (ctx->bytes >> 8);
+ ctx->buffer[58] = (u_char) (ctx->bytes >> 16);
+ ctx->buffer[59] = (u_char) (ctx->bytes >> 24);
+ ctx->buffer[60] = (u_char) (ctx->bytes >> 32);
+ ctx->buffer[61] = (u_char) (ctx->bytes >> 40);
+ ctx->buffer[62] = (u_char) (ctx->bytes >> 48);
+ ctx->buffer[63] = (u_char) (ctx->bytes >> 56);
+
+ (void) ngx_md5_body(ctx, ctx->buffer, 64);
+
+ result[0] = (u_char) ctx->a;
+ result[1] = (u_char) (ctx->a >> 8);
+ result[2] = (u_char) (ctx->a >> 16);
+ result[3] = (u_char) (ctx->a >> 24);
+ result[4] = (u_char) ctx->b;
+ result[5] = (u_char) (ctx->b >> 8);
+ result[6] = (u_char) (ctx->b >> 16);
+ result[7] = (u_char) (ctx->b >> 24);
+ result[8] = (u_char) ctx->c;
+ result[9] = (u_char) (ctx->c >> 8);
+ result[10] = (u_char) (ctx->c >> 16);
+ result[11] = (u_char) (ctx->c >> 24);
+ result[12] = (u_char) ctx->d;
+ result[13] = (u_char) (ctx->d >> 8);
+ result[14] = (u_char) (ctx->d >> 16);
+ result[15] = (u_char) (ctx->d >> 24);
+
+ ngx_memzero(ctx, sizeof(*ctx));
+}
+
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in
+ * Colin Plumb's implementation.
+ */
+
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b)
+
+/*
+ * SET() reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization. Nothing will break if it
+ * does not work.
+ */
+
+#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
+
+#define SET(n) (*(uint32_t *) &p[n * 4])
+#define GET(n) (*(uint32_t *) &p[n * 4])
+
+#else
+
+#define SET(n) \
+ (block[n] = \
+ (uint32_t) p[n * 4] | \
+ ((uint32_t) p[n * 4 + 1] << 8) | \
+ ((uint32_t) p[n * 4 + 2] << 16) | \
+ ((uint32_t) p[n * 4 + 3] << 24))
+
+#define GET(n) block[n]
+
+#endif
+
+
+/*
+ * This processes one or more 64-byte data blocks, but does not update
+ * the bit counters. There are no alignment requirements.
+ */
+
+static const u_char *
+ngx_md5_body(ngx_md5_t *ctx, const u_char *data, size_t size)
+{
+ uint32_t a, b, c, d;
+ uint32_t saved_a, saved_b, saved_c, saved_d;
+ const u_char *p;
+#if !(NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
+ uint32_t block[16];
+#endif
+
+ p = data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+ /* Round 1 */
+
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7);
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12);
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17);
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22);
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7);
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12);
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17);
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22);
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7);
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12);
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17);
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22);
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7);
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12);
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17);
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22);
+
+ /* Round 2 */
+
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5);
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9);
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14);
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20);
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5);
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9);
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14);
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20);
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5);
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9);
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14);
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20);
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5);
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9);
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14);
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20);
+
+ /* Round 3 */
+
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4);
+ STEP(H, d, a, b, c, GET(8), 0x8771f681, 11);
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16);
+ STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23);
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4);
+ STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11);
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16);
+ STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23);
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4);
+ STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11);
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16);
+ STEP(H, b, c, d, a, GET(6), 0x04881d05, 23);
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4);
+ STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11);
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16);
+ STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23);
+
+ /* Round 4 */
+
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6);
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10);
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15);
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21);
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6);
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10);
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15);
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21);
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6);
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10);
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15);
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21);
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6);
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10);
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15);
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21);
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ p += 64;
+
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return p;
+}
diff --git a/app/nginx/src/core/ngx_md5.h b/app/nginx/src/core/ngx_md5.h
new file mode 100644
index 0000000..713b614
--- /dev/null
+++ b/app/nginx/src/core/ngx_md5.h
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_MD5_H_INCLUDED_
+#define _NGX_MD5_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ uint64_t bytes;
+ uint32_t a, b, c, d;
+ u_char buffer[64];
+} ngx_md5_t;
+
+
+void ngx_md5_init(ngx_md5_t *ctx);
+void ngx_md5_update(ngx_md5_t *ctx, const void *data, size_t size);
+void ngx_md5_final(u_char result[16], ngx_md5_t *ctx);
+
+
+#endif /* _NGX_MD5_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_module.c b/app/nginx/src/core/ngx_module.c
new file mode 100644
index 0000000..3e3c506
--- /dev/null
+++ b/app/nginx/src/core/ngx_module.c
@@ -0,0 +1,360 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_MAX_DYNAMIC_MODULES 128
+
+
+static ngx_uint_t ngx_module_index(ngx_cycle_t *cycle);
+static ngx_uint_t ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type,
+ ngx_uint_t index);
+
+
+ngx_uint_t ngx_max_module;
+static ngx_uint_t ngx_modules_n;
+
+
+ngx_int_t
+ngx_preinit_modules(void)
+{
+ ngx_uint_t i;
+
+ for (i = 0; ngx_modules[i]; i++) {
+ ngx_modules[i]->index = i;
+ ngx_modules[i]->name = ngx_module_names[i];
+ }
+
+ ngx_modules_n = i;
+ ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_cycle_modules(ngx_cycle_t *cycle)
+{
+ /*
+ * create a list of modules to be used for this cycle,
+ * copy static modules to it
+ */
+
+ cycle->modules = ngx_pcalloc(cycle->pool, (ngx_max_module + 1)
+ * sizeof(ngx_module_t *));
+ if (cycle->modules == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(cycle->modules, ngx_modules,
+ ngx_modules_n * sizeof(ngx_module_t *));
+
+ cycle->modules_n = ngx_modules_n;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_init_modules(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+
+ for (i = 0; cycle->modules[i]; i++) {
+ if (cycle->modules[i]->init_module) {
+ if (cycle->modules[i]->init_module(cycle) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)
+{
+ ngx_uint_t i, next, max;
+ ngx_module_t *module;
+
+ next = 0;
+ max = 0;
+
+ /* count appropriate modules, set up their indices */
+
+ for (i = 0; cycle->modules[i]; i++) {
+ module = cycle->modules[i];
+
+ if (module->type != type) {
+ continue;
+ }
+
+ if (module->ctx_index != NGX_MODULE_UNSET_INDEX) {
+
+ /* if ctx_index was assigned, preserve it */
+
+ if (module->ctx_index > max) {
+ max = module->ctx_index;
+ }
+
+ if (module->ctx_index == next) {
+ next++;
+ }
+
+ continue;
+ }
+
+ /* search for some free index */
+
+ module->ctx_index = ngx_module_ctx_index(cycle, type, next);
+
+ if (module->ctx_index > max) {
+ max = module->ctx_index;
+ }
+
+ next = module->ctx_index + 1;
+ }
+
+ /*
+ * make sure the number returned is big enough for previous
+ * cycle as well, else there will be problems if the number
+ * will be stored in a global variable (as it's used to be)
+ * and we'll have to roll back to the previous cycle
+ */
+
+ if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+ for (i = 0; cycle->old_cycle->modules[i]; i++) {
+ module = cycle->old_cycle->modules[i];
+
+ if (module->type != type) {
+ continue;
+ }
+
+ if (module->ctx_index > max) {
+ max = module->ctx_index;
+ }
+ }
+ }
+
+ /* prevent loading of additional modules */
+
+ cycle->modules_used = 1;
+
+ return max + 1;
+}
+
+
+ngx_int_t
+ngx_add_module(ngx_conf_t *cf, ngx_str_t *file, ngx_module_t *module,
+ char **order)
+{
+ void *rv;
+ ngx_uint_t i, m, before;
+ ngx_core_module_t *core_module;
+
+ if (cf->cycle->modules_n >= ngx_max_module) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "too many modules loaded");
+ return NGX_ERROR;
+ }
+
+ if (module->version != nginx_version) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "module \"%V\" version %ui instead of %ui",
+ file, module->version, (ngx_uint_t) nginx_version);
+ return NGX_ERROR;
+ }
+
+ if (ngx_strcmp(module->signature, NGX_MODULE_SIGNATURE) != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "module \"%V\" is not binary compatible",
+ file);
+ return NGX_ERROR;
+ }
+
+ for (m = 0; cf->cycle->modules[m]; m++) {
+ if (ngx_strcmp(cf->cycle->modules[m]->name, module->name) == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "module \"%s\" is already loaded",
+ module->name);
+ return NGX_ERROR;
+ }
+ }
+
+ /*
+ * if the module wasn't previously loaded, assign an index
+ */
+
+ if (module->index == NGX_MODULE_UNSET_INDEX) {
+ module->index = ngx_module_index(cf->cycle);
+
+ if (module->index >= ngx_max_module) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "too many modules loaded");
+ return NGX_ERROR;
+ }
+ }
+
+ /*
+ * put the module into the cycle->modules array
+ */
+
+ before = cf->cycle->modules_n;
+
+ if (order) {
+ for (i = 0; order[i]; i++) {
+ if (ngx_strcmp(order[i], module->name) == 0) {
+ i++;
+ break;
+ }
+ }
+
+ for ( /* void */ ; order[i]; i++) {
+
+#if 0
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, cf->log, 0,
+ "module: %s before %s",
+ module->name, order[i]);
+#endif
+
+ for (m = 0; m < before; m++) {
+ if (ngx_strcmp(cf->cycle->modules[m]->name, order[i]) == 0) {
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, cf->log, 0,
+ "module: %s before %s:%i",
+ module->name, order[i], m);
+
+ before = m;
+ break;
+ }
+ }
+ }
+ }
+
+ /* put the module before modules[before] */
+
+ if (before != cf->cycle->modules_n) {
+ ngx_memmove(&cf->cycle->modules[before + 1],
+ &cf->cycle->modules[before],
+ (cf->cycle->modules_n - before) * sizeof(ngx_module_t *));
+ }
+
+ cf->cycle->modules[before] = module;
+ cf->cycle->modules_n++;
+
+ if (module->type == NGX_CORE_MODULE) {
+
+ /*
+ * we are smart enough to initialize core modules;
+ * other modules are expected to be loaded before
+ * initialization - e.g., http modules must be loaded
+ * before http{} block
+ */
+
+ core_module = module->ctx;
+
+ if (core_module->create_conf) {
+ rv = core_module->create_conf(cf->cycle);
+ if (rv == NULL) {
+ return NGX_ERROR;
+ }
+
+ cf->cycle->conf_ctx[module->index] = rv;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_uint_t
+ngx_module_index(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i, index;
+ ngx_module_t *module;
+
+ index = 0;
+
+again:
+
+ /* find an unused index */
+
+ for (i = 0; cycle->modules[i]; i++) {
+ module = cycle->modules[i];
+
+ if (module->index == index) {
+ index++;
+ goto again;
+ }
+ }
+
+ /* check previous cycle */
+
+ if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+ for (i = 0; cycle->old_cycle->modules[i]; i++) {
+ module = cycle->old_cycle->modules[i];
+
+ if (module->index == index) {
+ index++;
+ goto again;
+ }
+ }
+ }
+
+ return index;
+}
+
+
+static ngx_uint_t
+ngx_module_ctx_index(ngx_cycle_t *cycle, ngx_uint_t type, ngx_uint_t index)
+{
+ ngx_uint_t i;
+ ngx_module_t *module;
+
+again:
+
+ /* find an unused ctx_index */
+
+ for (i = 0; cycle->modules[i]; i++) {
+ module = cycle->modules[i];
+
+ if (module->type != type) {
+ continue;
+ }
+
+ if (module->ctx_index == index) {
+ index++;
+ goto again;
+ }
+ }
+
+ /* check previous cycle */
+
+ if (cycle->old_cycle && cycle->old_cycle->modules) {
+
+ for (i = 0; cycle->old_cycle->modules[i]; i++) {
+ module = cycle->old_cycle->modules[i];
+
+ if (module->type != type) {
+ continue;
+ }
+
+ if (module->ctx_index == index) {
+ index++;
+ goto again;
+ }
+ }
+ }
+
+ return index;
+}
diff --git a/app/nginx/src/core/ngx_module.h b/app/nginx/src/core/ngx_module.h
new file mode 100644
index 0000000..8cf3210
--- /dev/null
+++ b/app/nginx/src/core/ngx_module.h
@@ -0,0 +1,283 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_MODULE_H_INCLUDED_
+#define _NGX_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <nginx.h>
+
+
+#define NGX_MODULE_UNSET_INDEX (ngx_uint_t) -1
+
+
+#define NGX_MODULE_SIGNATURE_0 \
+ ngx_value(NGX_PTR_SIZE) "," \
+ ngx_value(NGX_SIG_ATOMIC_T_SIZE) "," \
+ ngx_value(NGX_TIME_T_SIZE) ","
+
+#if (NGX_HAVE_KQUEUE)
+#define NGX_MODULE_SIGNATURE_1 "1"
+#else
+#define NGX_MODULE_SIGNATURE_1 "0"
+#endif
+
+#if (NGX_HAVE_IOCP)
+#define NGX_MODULE_SIGNATURE_2 "1"
+#else
+#define NGX_MODULE_SIGNATURE_2 "0"
+#endif
+
+#if (NGX_HAVE_FILE_AIO || NGX_COMPAT)
+#define NGX_MODULE_SIGNATURE_3 "1"
+#else
+#define NGX_MODULE_SIGNATURE_3 "0"
+#endif
+
+#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT)
+#define NGX_MODULE_SIGNATURE_4 "1"
+#else
+#define NGX_MODULE_SIGNATURE_4 "0"
+#endif
+
+#if (NGX_HAVE_EVENTFD)
+#define NGX_MODULE_SIGNATURE_5 "1"
+#else
+#define NGX_MODULE_SIGNATURE_5 "0"
+#endif
+
+#if (NGX_HAVE_EPOLL)
+#define NGX_MODULE_SIGNATURE_6 "1"
+#else
+#define NGX_MODULE_SIGNATURE_6 "0"
+#endif
+
+#if (NGX_HAVE_KEEPALIVE_TUNABLE)
+#define NGX_MODULE_SIGNATURE_7 "1"
+#else
+#define NGX_MODULE_SIGNATURE_7 "0"
+#endif
+
+#if (NGX_HAVE_INET6)
+#define NGX_MODULE_SIGNATURE_8 "1"
+#else
+#define NGX_MODULE_SIGNATURE_8 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE_9 "1"
+#define NGX_MODULE_SIGNATURE_10 "1"
+
+#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
+#define NGX_MODULE_SIGNATURE_11 "1"
+#else
+#define NGX_MODULE_SIGNATURE_11 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE_12 "1"
+
+#if (NGX_HAVE_SETFIB)
+#define NGX_MODULE_SIGNATURE_13 "1"
+#else
+#define NGX_MODULE_SIGNATURE_13 "0"
+#endif
+
+#if (NGX_HAVE_TCP_FASTOPEN)
+#define NGX_MODULE_SIGNATURE_14 "1"
+#else
+#define NGX_MODULE_SIGNATURE_14 "0"
+#endif
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+#define NGX_MODULE_SIGNATURE_15 "1"
+#else
+#define NGX_MODULE_SIGNATURE_15 "0"
+#endif
+
+#if (NGX_HAVE_VARIADIC_MACROS)
+#define NGX_MODULE_SIGNATURE_16 "1"
+#else
+#define NGX_MODULE_SIGNATURE_16 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE_17 "0"
+#define NGX_MODULE_SIGNATURE_18 "0"
+
+#if (NGX_HAVE_OPENAT)
+#define NGX_MODULE_SIGNATURE_19 "1"
+#else
+#define NGX_MODULE_SIGNATURE_19 "0"
+#endif
+
+#if (NGX_HAVE_ATOMIC_OPS)
+#define NGX_MODULE_SIGNATURE_20 "1"
+#else
+#define NGX_MODULE_SIGNATURE_20 "0"
+#endif
+
+#if (NGX_HAVE_POSIX_SEM)
+#define NGX_MODULE_SIGNATURE_21 "1"
+#else
+#define NGX_MODULE_SIGNATURE_21 "0"
+#endif
+
+#if (NGX_THREADS || NGX_COMPAT)
+#define NGX_MODULE_SIGNATURE_22 "1"
+#else
+#define NGX_MODULE_SIGNATURE_22 "0"
+#endif
+
+#if (NGX_PCRE)
+#define NGX_MODULE_SIGNATURE_23 "1"
+#else
+#define NGX_MODULE_SIGNATURE_23 "0"
+#endif
+
+#if (NGX_HTTP_SSL || NGX_COMPAT)
+#define NGX_MODULE_SIGNATURE_24 "1"
+#else
+#define NGX_MODULE_SIGNATURE_24 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE_25 "1"
+
+#if (NGX_HTTP_GZIP)
+#define NGX_MODULE_SIGNATURE_26 "1"
+#else
+#define NGX_MODULE_SIGNATURE_26 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE_27 "1"
+
+#if (NGX_HTTP_X_FORWARDED_FOR)
+#define NGX_MODULE_SIGNATURE_28 "1"
+#else
+#define NGX_MODULE_SIGNATURE_28 "0"
+#endif
+
+#if (NGX_HTTP_REALIP)
+#define NGX_MODULE_SIGNATURE_29 "1"
+#else
+#define NGX_MODULE_SIGNATURE_29 "0"
+#endif
+
+#if (NGX_HTTP_HEADERS)
+#define NGX_MODULE_SIGNATURE_30 "1"
+#else
+#define NGX_MODULE_SIGNATURE_30 "0"
+#endif
+
+#if (NGX_HTTP_DAV)
+#define NGX_MODULE_SIGNATURE_31 "1"
+#else
+#define NGX_MODULE_SIGNATURE_31 "0"
+#endif
+
+#if (NGX_HTTP_CACHE)
+#define NGX_MODULE_SIGNATURE_32 "1"
+#else
+#define NGX_MODULE_SIGNATURE_32 "0"
+#endif
+
+#if (NGX_HTTP_UPSTREAM_ZONE)
+#define NGX_MODULE_SIGNATURE_33 "1"
+#else
+#define NGX_MODULE_SIGNATURE_33 "0"
+#endif
+
+#if (NGX_COMPAT)
+#define NGX_MODULE_SIGNATURE_34 "1"
+#else
+#define NGX_MODULE_SIGNATURE_34 "0"
+#endif
+
+#define NGX_MODULE_SIGNATURE \
+ NGX_MODULE_SIGNATURE_0 NGX_MODULE_SIGNATURE_1 NGX_MODULE_SIGNATURE_2 \
+ NGX_MODULE_SIGNATURE_3 NGX_MODULE_SIGNATURE_4 NGX_MODULE_SIGNATURE_5 \
+ NGX_MODULE_SIGNATURE_6 NGX_MODULE_SIGNATURE_7 NGX_MODULE_SIGNATURE_8 \
+ NGX_MODULE_SIGNATURE_9 NGX_MODULE_SIGNATURE_10 NGX_MODULE_SIGNATURE_11 \
+ NGX_MODULE_SIGNATURE_12 NGX_MODULE_SIGNATURE_13 NGX_MODULE_SIGNATURE_14 \
+ NGX_MODULE_SIGNATURE_15 NGX_MODULE_SIGNATURE_16 NGX_MODULE_SIGNATURE_17 \
+ NGX_MODULE_SIGNATURE_18 NGX_MODULE_SIGNATURE_19 NGX_MODULE_SIGNATURE_20 \
+ NGX_MODULE_SIGNATURE_21 NGX_MODULE_SIGNATURE_22 NGX_MODULE_SIGNATURE_23 \
+ NGX_MODULE_SIGNATURE_24 NGX_MODULE_SIGNATURE_25 NGX_MODULE_SIGNATURE_26 \
+ NGX_MODULE_SIGNATURE_27 NGX_MODULE_SIGNATURE_28 NGX_MODULE_SIGNATURE_29 \
+ NGX_MODULE_SIGNATURE_30 NGX_MODULE_SIGNATURE_31 NGX_MODULE_SIGNATURE_32 \
+ NGX_MODULE_SIGNATURE_33 NGX_MODULE_SIGNATURE_34
+
+
+#define NGX_MODULE_V1 \
+ NGX_MODULE_UNSET_INDEX, NGX_MODULE_UNSET_INDEX, \
+ NULL, 0, 0, nginx_version, NGX_MODULE_SIGNATURE
+
+#define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0
+
+
+struct ngx_module_s {
+ ngx_uint_t ctx_index;
+ ngx_uint_t index;
+
+ char *name;
+
+ ngx_uint_t spare0;
+ ngx_uint_t spare1;
+
+ ngx_uint_t version;
+ const char *signature;
+
+ void *ctx;
+ ngx_command_t *commands;
+ ngx_uint_t type;
+
+ ngx_int_t (*init_master)(ngx_log_t *log);
+
+ ngx_int_t (*init_module)(ngx_cycle_t *cycle);
+
+ ngx_int_t (*init_process)(ngx_cycle_t *cycle);
+ ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
+ void (*exit_thread)(ngx_cycle_t *cycle);
+ void (*exit_process)(ngx_cycle_t *cycle);
+
+ void (*exit_master)(ngx_cycle_t *cycle);
+
+ uintptr_t spare_hook0;
+ uintptr_t spare_hook1;
+ uintptr_t spare_hook2;
+ uintptr_t spare_hook3;
+ uintptr_t spare_hook4;
+ uintptr_t spare_hook5;
+ uintptr_t spare_hook6;
+ uintptr_t spare_hook7;
+};
+
+
+typedef struct {
+ ngx_str_t name;
+ void *(*create_conf)(ngx_cycle_t *cycle);
+ char *(*init_conf)(ngx_cycle_t *cycle, void *conf);
+} ngx_core_module_t;
+
+
+ngx_int_t ngx_preinit_modules(void);
+ngx_int_t ngx_cycle_modules(ngx_cycle_t *cycle);
+ngx_int_t ngx_init_modules(ngx_cycle_t *cycle);
+ngx_int_t ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type);
+
+
+ngx_int_t ngx_add_module(ngx_conf_t *cf, ngx_str_t *file,
+ ngx_module_t *module, char **order);
+
+
+extern ngx_module_t *ngx_modules[];
+extern ngx_uint_t ngx_max_module;
+
+extern char *ngx_module_names[];
+
+
+#endif /* _NGX_MODULE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_murmurhash.c b/app/nginx/src/core/ngx_murmurhash.c
new file mode 100644
index 0000000..c31e0e0
--- /dev/null
+++ b/app/nginx/src/core/ngx_murmurhash.c
@@ -0,0 +1,50 @@
+
+/*
+ * Copyright (C) Austin Appleby
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+uint32_t
+ngx_murmur_hash2(u_char *data, size_t len)
+{
+ uint32_t h, k;
+
+ h = 0 ^ len;
+
+ while (len >= 4) {
+ k = data[0];
+ k |= data[1] << 8;
+ k |= data[2] << 16;
+ k |= data[3] << 24;
+
+ k *= 0x5bd1e995;
+ k ^= k >> 24;
+ k *= 0x5bd1e995;
+
+ h *= 0x5bd1e995;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ switch (len) {
+ case 3:
+ h ^= data[2] << 16;
+ case 2:
+ h ^= data[1] << 8;
+ case 1:
+ h ^= data[0];
+ h *= 0x5bd1e995;
+ }
+
+ h ^= h >> 13;
+ h *= 0x5bd1e995;
+ h ^= h >> 15;
+
+ return h;
+}
diff --git a/app/nginx/src/core/ngx_murmurhash.h b/app/nginx/src/core/ngx_murmurhash.h
new file mode 100644
index 0000000..54e867d
--- /dev/null
+++ b/app/nginx/src/core/ngx_murmurhash.h
@@ -0,0 +1,19 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_MURMURHASH_H_INCLUDED_
+#define _NGX_MURMURHASH_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+uint32_t ngx_murmur_hash2(u_char *data, size_t len);
+
+
+#endif /* _NGX_MURMURHASH_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_open_file_cache.c b/app/nginx/src/core/ngx_open_file_cache.c
new file mode 100644
index 0000000..b23ee78
--- /dev/null
+++ b/app/nginx/src/core/ngx_open_file_cache.c
@@ -0,0 +1,1253 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * open file cache caches
+ * open file handles with stat() info;
+ * directories stat() info;
+ * files and directories errors: not found, access denied, etc.
+ */
+
+
+#define NGX_MIN_READ_AHEAD (128 * 1024)
+
+
+static void ngx_open_file_cache_cleanup(void *data);
+#if (NGX_HAVE_OPENAT)
+static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
+ ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log);
+#if (NGX_HAVE_O_PATH)
+static ngx_int_t ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi,
+ ngx_log_t *log);
+#endif
+#endif
+static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create,
+ ngx_int_t access, ngx_log_t *log);
+static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log);
+static ngx_int_t ngx_open_and_stat_file(ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_log_t *log);
+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);
+static void ngx_open_file_cleanup(void *data);
+static void ngx_close_cached_file(ngx_open_file_cache_t *cache,
+ ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log);
+static void ngx_open_file_del_event(ngx_cached_open_file_t *file);
+static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache,
+ ngx_uint_t n, ngx_log_t *log);
+static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_cached_open_file_t *
+ ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
+ uint32_t hash);
+static void ngx_open_file_cache_remove(ngx_event_t *ev);
+
+
+ngx_open_file_cache_t *
+ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive)
+{
+ ngx_pool_cleanup_t *cln;
+ ngx_open_file_cache_t *cache;
+
+ cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t));
+ if (cache == NULL) {
+ return NULL;
+ }
+
+ ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
+ ngx_open_file_cache_rbtree_insert_value);
+
+ ngx_queue_init(&cache->expire_queue);
+
+ cache->current = 0;
+ cache->max = max;
+ cache->inactive = inactive;
+
+ cln = ngx_pool_cleanup_add(pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_open_file_cache_cleanup;
+ cln->data = cache;
+
+ return cache;
+}
+
+
+static void
+ngx_open_file_cache_cleanup(void *data)
+{
+ ngx_open_file_cache_t *cache = data;
+
+ ngx_queue_t *q;
+ ngx_cached_open_file_t *file;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "open file cache cleanup");
+
+ for ( ;; ) {
+
+ if (ngx_queue_empty(&cache->expire_queue)) {
+ break;
+ }
+
+ q = ngx_queue_last(&cache->expire_queue);
+
+ file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "delete cached open file: %s", file->name);
+
+ if (!file->err && !file->is_dir) {
+ file->close = 1;
+ file->count = 0;
+ ngx_close_cached_file(cache, file, 0, ngx_cycle->log);
+
+ } else {
+ ngx_free(file->name);
+ ngx_free(file);
+ }
+ }
+
+ if (cache->current) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%ui items still left in open file cache",
+ cache->current);
+ }
+
+ if (cache->rbtree.root != cache->rbtree.sentinel) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "rbtree still is not empty in open file cache");
+
+ }
+}
+
+
+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;
+}
+
+
+#if (NGX_HAVE_OPENAT)
+
+static ngx_fd_t
+ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name,
+ ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log)
+{
+ ngx_fd_t fd;
+ ngx_err_t err;
+ ngx_file_info_t fi, atfi;
+
+ /*
+ * To allow symlinks with the same owner, use openat() (followed
+ * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare
+ * uids between fstat() and fstatat().
+ *
+ * As there is a race between openat() and fstatat() we don't
+ * know if openat() in fact opened symlink or not. Therefore,
+ * we have to compare uids even if fstatat() reports the opened
+ * component isn't a symlink (as we don't know whether it was
+ * symlink during openat() or not).
+ */
+
+ fd = ngx_openat_file(at_fd, name, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ return NGX_INVALID_FILE;
+ }
+
+ if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW)
+ == NGX_FILE_ERROR)
+ {
+ err = ngx_errno;
+ goto failed;
+ }
+
+#if (NGX_HAVE_O_PATH)
+ if (ngx_file_o_path_info(fd, &fi, log) == NGX_ERROR) {
+ err = ngx_errno;
+ goto failed;
+ }
+#else
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+ goto failed;
+ }
+#endif
+
+ if (fi.st_uid != atfi.st_uid) {
+ err = NGX_ELOOP;
+ goto failed;
+ }
+
+ return fd;
+
+failed:
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", name);
+ }
+
+ ngx_set_errno(err);
+
+ return NGX_INVALID_FILE;
+}
+
+
+#if (NGX_HAVE_O_PATH)
+
+static ngx_int_t
+ngx_file_o_path_info(ngx_fd_t fd, ngx_file_info_t *fi, ngx_log_t *log)
+{
+ static ngx_uint_t use_fstat = 1;
+
+ /*
+ * In Linux 2.6.39 the O_PATH flag was introduced that allows to obtain
+ * a descriptor without actually opening file or directory. It requires
+ * less permissions for path components, but till Linux 3.6 fstat() returns
+ * EBADF on such descriptors, and fstatat() with the AT_EMPTY_PATH flag
+ * should be used instead.
+ *
+ * Three scenarios are handled in this function:
+ *
+ * 1) The kernel is newer than 3.6 or fstat() with O_PATH support was
+ * backported by vendor. Then fstat() is used.
+ *
+ * 2) The kernel is newer than 2.6.39 but older than 3.6. In this case
+ * the first call of fstat() returns EBADF and we fallback to fstatat()
+ * with AT_EMPTY_PATH which was introduced at the same time as O_PATH.
+ *
+ * 3) The kernel is older than 2.6.39 but nginx was build with O_PATH
+ * support. Since descriptors are opened with O_PATH|O_RDONLY flags
+ * and O_PATH is ignored by the kernel then the O_RDONLY flag is
+ * actually used. In this case fstat() just works.
+ */
+
+ if (use_fstat) {
+ if (ngx_fd_info(fd, fi) != NGX_FILE_ERROR) {
+ return NGX_OK;
+ }
+
+ if (ngx_errno != NGX_EBADF) {
+ return NGX_ERROR;
+ }
+
+ ngx_log_error(NGX_LOG_NOTICE, log, 0,
+ "fstat(O_PATH) failed with EBADF, "
+ "switching to fstatat(AT_EMPTY_PATH)");
+
+ use_fstat = 0;
+ }
+
+ if (ngx_file_at_info(fd, "", fi, AT_EMPTY_PATH) != NGX_FILE_ERROR) {
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+}
+
+#endif
+
+#endif /* NGX_HAVE_OPENAT */
+
+
+static ngx_fd_t
+ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
+ ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log)
+{
+ ngx_fd_t fd;
+
+#if !(NGX_HAVE_OPENAT)
+
+ fd = ngx_open_file(name->data, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ return fd;
+
+#else
+
+ u_char *p, *cp, *end;
+ ngx_fd_t at_fd;
+ ngx_str_t at_name;
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
+ fd = ngx_open_file(name->data, mode, create, access);
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ return fd;
+ }
+
+ p = name->data;
+ end = p + name->len;
+
+ at_name = *name;
+
+ if (of->disable_symlinks_from) {
+
+ cp = p + of->disable_symlinks_from;
+
+ *cp = '\0';
+
+ at_fd = ngx_open_file(p, NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0);
+
+ *cp = '/';
+
+ if (at_fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_open_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ at_name.len = of->disable_symlinks_from;
+ p = cp + 1;
+
+ } else if (*p == '/') {
+
+ at_fd = ngx_open_file("/",
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0);
+
+ if (at_fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ return NGX_INVALID_FILE;
+ }
+
+ at_name.len = 1;
+ p++;
+
+ } else {
+ at_fd = NGX_AT_FDCWD;
+ }
+
+ for ( ;; ) {
+ cp = ngx_strlchr(p, end, '/');
+ if (cp == NULL) {
+ break;
+ }
+
+ if (cp == p) {
+ p++;
+ continue;
+ }
+
+ *cp = '\0';
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) {
+ fd = ngx_openat_file_owner(at_fd, p,
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
+
+ } else {
+ fd = ngx_openat_file(at_fd, p,
+ NGX_FILE_SEARCH|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW,
+ NGX_FILE_OPEN, 0);
+ }
+
+ *cp = '/';
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ goto failed;
+ }
+
+ if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &at_name);
+ }
+
+ p = cp + 1;
+ at_fd = fd;
+ at_name.len = cp - at_name.data;
+ }
+
+ if (p == end) {
+
+ /*
+ * If pathname ends with a trailing slash, assume the last path
+ * component is a directory and reopen it with requested flags;
+ * if not, fail with ENOTDIR as per POSIX.
+ *
+ * We cannot rely on O_DIRECTORY in the loop above to check
+ * that the last path component is a directory because
+ * O_DIRECTORY doesn't work on FreeBSD 8. Fortunately, by
+ * reopening a directory, we don't depend on it at all.
+ */
+
+ fd = ngx_openat_file(at_fd, ".", mode, create, access);
+ goto done;
+ }
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER
+ && !(create & (NGX_FILE_CREATE_OR_OPEN|NGX_FILE_TRUNCATE)))
+ {
+ fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log);
+
+ } else {
+ fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access);
+ }
+
+done:
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ of->failed = ngx_openat_file_n;
+ }
+
+failed:
+
+ if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", &at_name);
+ }
+
+ return fd;
+#endif
+}
+
+
+static ngx_int_t
+ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of,
+ ngx_file_info_t *fi, ngx_log_t *log)
+{
+ ngx_int_t rc;
+
+#if !(NGX_HAVE_OPENAT)
+
+ rc = ngx_file_info(name->data, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_file_info_n;
+ return NGX_FILE_ERROR;
+ }
+
+ return rc;
+
+#else
+
+ ngx_fd_t fd;
+
+ if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) {
+
+ rc = ngx_file_info(name->data, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_file_info_n;
+ return NGX_FILE_ERROR;
+ }
+
+ return rc;
+ }
+
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
+
+ if (fd == NGX_INVALID_FILE) {
+ return NGX_FILE_ERROR;
+ }
+
+ rc = ngx_fd_info(fd, fi);
+
+ if (rc == NGX_FILE_ERROR) {
+ of->err = ngx_errno;
+ of->failed = ngx_fd_info_n;
+ }
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", name);
+ }
+
+ return rc;
+#endif
+}
+
+
+static ngx_int_t
+ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of,
+ ngx_log_t *log)
+{
+ ngx_fd_t fd;
+ ngx_file_info_t fi;
+
+ if (of->fd != NGX_INVALID_FILE) {
+
+ if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
+ }
+
+ if (of->uniq == ngx_file_uniq(&fi)) {
+ goto done;
+ }
+
+ } else if (of->test_dir) {
+
+ if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) {
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
+ }
+
+ if (ngx_is_dir(&fi)) {
+ goto done;
+ }
+ }
+
+ if (!of->log) {
+
+ /*
+ * Use non-blocking open() not to hang on FIFO files, etc.
+ * This flag has no effect on a regular files.
+ */
+
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK,
+ NGX_FILE_OPEN, 0, log);
+
+ } else {
+ fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND,
+ NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS, log);
+ }
+
+ if (fd == NGX_INVALID_FILE) {
+ of->fd = NGX_INVALID_FILE;
+ return NGX_ERROR;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+ ngx_fd_info_n " \"%V\" failed", name);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", name);
+ }
+
+ of->fd = NGX_INVALID_FILE;
+
+ return NGX_ERROR;
+ }
+
+ if (ngx_is_dir(&fi)) {
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%V\" failed", name);
+ }
+
+ of->fd = NGX_INVALID_FILE;
+
+ } else {
+ of->fd = fd;
+
+ if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) {
+ if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_read_ahead_n " \"%V\" failed", name);
+ }
+ }
+
+ if (of->directio <= ngx_file_size(&fi)) {
+ if (ngx_directio_on(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_directio_on_n " \"%V\" failed", name);
+
+ } else {
+ of->is_directio = 1;
+ }
+ }
+ }
+
+done:
+
+ 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;
+}
+
+
+/*
+ * we ignore any possible event setting error and
+ * fallback to usual periodic file retests
+ */
+
+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 void
+ngx_open_file_cleanup(void *data)
+{
+ ngx_open_file_cache_cleanup_t *c = data;
+
+ c->file->count--;
+
+ ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log);
+
+ /* drop one or two expired open files */
+ ngx_expire_old_cached_files(c->cache, 1, c->log);
+}
+
+
+static void
+ngx_close_cached_file(ngx_open_file_cache_t *cache,
+ ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log)
+{
+ ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0,
+ "close cached open file: %s, fd:%d, c:%d, u:%d, %d",
+ file->name, file->fd, file->count, file->uses, file->close);
+
+ if (!file->close) {
+
+ file->accessed = ngx_time();
+
+ ngx_queue_remove(&file->queue);
+
+ ngx_queue_insert_head(&cache->expire_queue, &file->queue);
+
+ if (file->uses >= min_uses || file->count) {
+ return;
+ }
+ }
+
+ ngx_open_file_del_event(file);
+
+ if (file->count) {
+ return;
+ }
+
+ if (file->fd != NGX_INVALID_FILE) {
+
+ if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file->name);
+ }
+
+ file->fd = NGX_INVALID_FILE;
+ }
+
+ if (!file->close) {
+ return;
+ }
+
+ ngx_free(file->name);
+ ngx_free(file);
+}
+
+
+static void
+ngx_open_file_del_event(ngx_cached_open_file_t *file)
+{
+ if (file->event == NULL) {
+ return;
+ }
+
+ (void) ngx_del_event(file->event, NGX_VNODE_EVENT,
+ file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT);
+
+ ngx_free(file->event->data);
+ ngx_free(file->event);
+ file->event = NULL;
+ file->use_event = 0;
+}
+
+
+static void
+ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n,
+ ngx_log_t *log)
+{
+ time_t now;
+ ngx_queue_t *q;
+ ngx_cached_open_file_t *file;
+
+ now = ngx_time();
+
+ /*
+ * n == 1 deletes one or two inactive files
+ * n == 0 deletes least recently used file by force
+ * and one or two inactive files
+ */
+
+ while (n < 3) {
+
+ if (ngx_queue_empty(&cache->expire_queue)) {
+ return;
+ }
+
+ q = ngx_queue_last(&cache->expire_queue);
+
+ file = ngx_queue_data(q, ngx_cached_open_file_t, queue);
+
+ if (n++ != 0 && now - file->accessed <= cache->inactive) {
+ return;
+ }
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "expire cached open file: %s", file->name);
+
+ if (!file->err && !file->is_dir) {
+ file->close = 1;
+ ngx_close_cached_file(cache, file, 0, log);
+
+ } else {
+ ngx_free(file->name);
+ ngx_free(file);
+ }
+ }
+}
+
+
+static void
+ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_cached_open_file_t *file, *file_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ file = (ngx_cached_open_file_t *) node;
+ file_temp = (ngx_cached_open_file_t *) temp;
+
+ p = (ngx_strcmp(file->name, file_temp->name) < 0)
+ ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+static ngx_cached_open_file_t *
+ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name,
+ uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_cached_open_file_t *file;
+
+ node = cache->rbtree.root;
+ sentinel = cache->rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ file = (ngx_cached_open_file_t *) node;
+
+ rc = ngx_strcmp(name->data, file->name);
+
+ if (rc == 0) {
+ return file;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ return NULL;
+}
+
+
+static void
+ngx_open_file_cache_remove(ngx_event_t *ev)
+{
+ ngx_cached_open_file_t *file;
+ ngx_open_file_cache_event_t *fev;
+
+ fev = ev->data;
+ file = fev->file;
+
+ ngx_queue_remove(&file->queue);
+
+ ngx_rbtree_delete(&fev->cache->rbtree, &file->node);
+
+ fev->cache->current--;
+
+ /* NGX_ONESHOT_EVENT was already deleted */
+ file->event = NULL;
+ file->use_event = 0;
+
+ file->close = 1;
+
+ ngx_close_cached_file(fev->cache, file, 0, ev->log);
+
+ /* free memory only when fev->cache and fev->file are already not needed */
+
+ ngx_free(ev->data);
+ ngx_free(ev);
+}
diff --git a/app/nginx/src/core/ngx_open_file_cache.h b/app/nginx/src/core/ngx_open_file_cache.h
new file mode 100644
index 0000000..d119c12
--- /dev/null
+++ b/app/nginx/src/core/ngx_open_file_cache.h
@@ -0,0 +1,129 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#ifndef _NGX_OPEN_FILE_CACHE_H_INCLUDED_
+#define _NGX_OPEN_FILE_CACHE_H_INCLUDED_
+
+
+#define NGX_OPEN_FILE_DIRECTIO_OFF NGX_MAX_OFF_T_VALUE
+
+
+typedef struct {
+ ngx_fd_t fd;
+ ngx_file_uniq_t uniq;
+ time_t mtime;
+ off_t size;
+ off_t fs_size;
+ off_t directio;
+ size_t read_ahead;
+
+ ngx_err_t err;
+ char *failed;
+
+ time_t valid;
+
+ ngx_uint_t min_uses;
+
+#if (NGX_HAVE_OPENAT)
+ size_t disable_symlinks_from;
+ unsigned disable_symlinks:2;
+#endif
+
+ unsigned test_dir:1;
+ unsigned test_only:1;
+ unsigned log:1;
+ unsigned errors:1;
+ unsigned events:1;
+
+ unsigned is_dir:1;
+ unsigned is_file:1;
+ unsigned is_link:1;
+ unsigned is_exec:1;
+ unsigned is_directio:1;
+} ngx_open_file_info_t;
+
+
+typedef struct ngx_cached_open_file_s ngx_cached_open_file_t;
+
+struct ngx_cached_open_file_s {
+ ngx_rbtree_node_t node;
+ ngx_queue_t queue;
+
+ u_char *name;
+ time_t created;
+ time_t accessed;
+
+ ngx_fd_t fd;
+ ngx_file_uniq_t uniq;
+ time_t mtime;
+ off_t size;
+ ngx_err_t err;
+
+ uint32_t uses;
+
+#if (NGX_HAVE_OPENAT)
+ size_t disable_symlinks_from;
+ unsigned disable_symlinks:2;
+#endif
+
+ unsigned count:24;
+ unsigned close:1;
+ unsigned use_event:1;
+
+ unsigned is_dir:1;
+ unsigned is_file:1;
+ unsigned is_link:1;
+ unsigned is_exec:1;
+ unsigned is_directio:1;
+
+ ngx_event_t *event;
+};
+
+
+typedef struct {
+ ngx_rbtree_t rbtree;
+ ngx_rbtree_node_t sentinel;
+ ngx_queue_t expire_queue;
+
+ ngx_uint_t current;
+ ngx_uint_t max;
+ time_t inactive;
+} ngx_open_file_cache_t;
+
+
+typedef struct {
+ ngx_open_file_cache_t *cache;
+ ngx_cached_open_file_t *file;
+ ngx_uint_t min_uses;
+ ngx_log_t *log;
+} ngx_open_file_cache_cleanup_t;
+
+
+typedef struct {
+
+ /* ngx_connection_t stub to allow use c->fd as event ident */
+ void *data;
+ ngx_event_t *read;
+ ngx_event_t *write;
+ ngx_fd_t fd;
+
+ ngx_cached_open_file_t *file;
+ ngx_open_file_cache_t *cache;
+} ngx_open_file_cache_event_t;
+
+
+ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool,
+ ngx_uint_t max, time_t inactive);
+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);
+
+
+#endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_output_chain.c b/app/nginx/src/core/ngx_output_chain.c
new file mode 100644
index 0000000..7f5dc78
--- /dev/null
+++ b/app/nginx/src/core/ngx_output_chain.c
@@ -0,0 +1,767 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#if 0
+#define NGX_SENDFILE_LIMIT 4096
+#endif
+
+/*
+ * When DIRECTIO is enabled FreeBSD, Solaris, and MacOSX read directly
+ * to an application memory from a device if parameters are aligned
+ * to device sector boundary (512 bytes). They fallback to usual read
+ * operation if the parameters are not aligned.
+ * Linux allows DIRECTIO only if the parameters are aligned to a filesystem
+ * sector boundary, otherwise it returns EINVAL. The sector size is
+ * usually 512 bytes, however, on XFS it may be 4096 bytes.
+ */
+
+#define NGX_NONE 1
+
+
+static ngx_inline ngx_int_t
+ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf);
+#if (NGX_HAVE_AIO_SENDFILE)
+static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx,
+ ngx_file_t *file);
+#endif
+static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool,
+ ngx_chain_t **chain, ngx_chain_t *in);
+static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx,
+ off_t bsize);
+static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx,
+ off_t bsize);
+static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx);
+
+
+ngx_int_t
+ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in)
+{
+ off_t bsize;
+ ngx_int_t rc, last;
+ ngx_chain_t *cl, *out, **last_out;
+
+ if (ctx->in == NULL && ctx->busy == NULL
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
+ && !ctx->aio
+#endif
+ )
+ {
+ /*
+ * the short path for the case when the ctx->in and ctx->busy chains
+ * are empty, the incoming chain is empty too or has the single buf
+ * that does not require the copy
+ */
+
+ if (in == NULL) {
+ return ctx->output_filter(ctx->filter_ctx, in);
+ }
+
+ if (in->next == NULL
+#if (NGX_SENDFILE_LIMIT)
+ && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT)
+#endif
+ && ngx_output_chain_as_is(ctx, in->buf))
+ {
+ return ctx->output_filter(ctx->filter_ctx, in);
+ }
+ }
+
+ /* add the incoming buf to the chain ctx->in */
+
+ if (in) {
+ if (ngx_output_chain_add_copy(ctx->pool, &ctx->in, in) == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+ }
+
+ out = NULL;
+ last_out = &out;
+ last = NGX_NONE;
+
+ for ( ;; ) {
+
+#if (NGX_HAVE_FILE_AIO || NGX_THREADS)
+ if (ctx->aio) {
+ return NGX_AGAIN;
+ }
+#endif
+
+ while (ctx->in) {
+
+ /*
+ * cycle while there are the ctx->in bufs
+ * and there are the free output bufs to copy in
+ */
+
+ bsize = ngx_buf_size(ctx->in->buf);
+
+ if (bsize == 0 && !ngx_buf_special(ctx->in->buf)) {
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ "zero size buf in output "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ ctx->in->buf->temporary,
+ ctx->in->buf->recycled,
+ ctx->in->buf->in_file,
+ ctx->in->buf->start,
+ ctx->in->buf->pos,
+ ctx->in->buf->last,
+ ctx->in->buf->file,
+ ctx->in->buf->file_pos,
+ ctx->in->buf->file_last);
+
+ ngx_debug_point();
+
+ ctx->in = ctx->in->next;
+
+ continue;
+ }
+
+ if (ngx_output_chain_as_is(ctx, ctx->in->buf)) {
+
+ /* move the chain link to the output chain */
+
+ cl = ctx->in;
+ ctx->in = cl->next;
+
+ *last_out = cl;
+ last_out = &cl->next;
+ cl->next = NULL;
+
+ continue;
+ }
+
+ if (ctx->buf == NULL) {
+
+ rc = ngx_output_chain_align_file_buf(ctx, bsize);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc != NGX_OK) {
+
+ if (ctx->free) {
+
+ /* get the free buf */
+
+ cl = ctx->free;
+ ctx->buf = cl->buf;
+ ctx->free = cl->next;
+
+ ngx_free_chain(ctx->pool, cl);
+
+ } else if (out || ctx->allocated == ctx->bufs.num) {
+
+ break;
+
+ } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+ }
+
+ rc = ngx_output_chain_copy_buf(ctx);
+
+ if (rc == NGX_ERROR) {
+ return rc;
+ }
+
+ if (rc == NGX_AGAIN) {
+ if (out) {
+ break;
+ }
+
+ return rc;
+ }
+
+ /* delete the completed buf from the ctx->in chain */
+
+ if (ngx_buf_size(ctx->in->buf) == 0) {
+ ctx->in = ctx->in->next;
+ }
+
+ cl = ngx_alloc_chain_link(ctx->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = ctx->buf;
+ cl->next = NULL;
+ *last_out = cl;
+ last_out = &cl->next;
+ ctx->buf = NULL;
+ }
+
+ if (out == NULL && last != NGX_NONE) {
+
+ if (ctx->in) {
+ return NGX_AGAIN;
+ }
+
+ return last;
+ }
+
+ last = ctx->output_filter(ctx->filter_ctx, out);
+
+ if (last == NGX_ERROR || last == NGX_DONE) {
+ return last;
+ }
+
+ ngx_chain_update_chains(ctx->pool, &ctx->free, &ctx->busy, &out,
+ ctx->tag);
+ last_out = &out;
+ }
+}
+
+
+static ngx_inline ngx_int_t
+ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf)
+{
+ ngx_uint_t sendfile;
+
+ if (ngx_buf_special(buf)) {
+ return 1;
+ }
+
+#if (NGX_THREADS)
+ if (buf->in_file) {
+ buf->file->thread_handler = ctx->thread_handler;
+ buf->file->thread_ctx = ctx->filter_ctx;
+ }
+#endif
+
+ if (buf->in_file && buf->file->directio) {
+ return 0;
+ }
+
+ sendfile = ctx->sendfile;
+
+#if (NGX_SENDFILE_LIMIT)
+
+ if (buf->in_file && buf->file_pos >= NGX_SENDFILE_LIMIT) {
+ sendfile = 0;
+ }
+
+#endif
+
+ if (!sendfile) {
+
+ if (!ngx_buf_in_memory(buf)) {
+ return 0;
+ }
+
+ buf->in_file = 0;
+ }
+
+#if (NGX_HAVE_AIO_SENDFILE)
+ if (ctx->aio_preload && buf->in_file) {
+ (void) ngx_output_chain_aio_setup(ctx, buf->file);
+ }
+#endif
+
+ if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) {
+ return 0;
+ }
+
+ if (ctx->need_in_temp && (buf->memory || buf->mmap)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
+#if (NGX_HAVE_AIO_SENDFILE)
+
+static ngx_int_t
+ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file)
+{
+ ngx_event_aio_t *aio;
+
+ if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ aio = file->aio;
+
+ aio->data = ctx->filter_ctx;
+ aio->preload_handler = ctx->aio_preload;
+
+ return NGX_OK;
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain,
+ ngx_chain_t *in)
+{
+ ngx_chain_t *cl, **ll;
+#if (NGX_SENDFILE_LIMIT)
+ ngx_buf_t *b, *buf;
+#endif
+
+ ll = chain;
+
+ for (cl = *chain; cl; cl = cl->next) {
+ ll = &cl->next;
+ }
+
+ while (in) {
+
+ cl = ngx_alloc_chain_link(pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+#if (NGX_SENDFILE_LIMIT)
+
+ buf = in->buf;
+
+ if (buf->in_file
+ && buf->file_pos < NGX_SENDFILE_LIMIT
+ && buf->file_last > NGX_SENDFILE_LIMIT)
+ {
+ /* split a file buf on two bufs by the sendfile limit */
+
+ b = ngx_calloc_buf(pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(b, buf, sizeof(ngx_buf_t));
+
+ if (ngx_buf_in_memory(buf)) {
+ buf->pos += (ssize_t) (NGX_SENDFILE_LIMIT - buf->file_pos);
+ b->last = buf->pos;
+ }
+
+ buf->file_pos = NGX_SENDFILE_LIMIT;
+ b->file_last = NGX_SENDFILE_LIMIT;
+
+ cl->buf = b;
+
+ } else {
+ cl->buf = buf;
+ in = in->next;
+ }
+
+#else
+ cl->buf = in->buf;
+ in = in->next;
+
+#endif
+
+ cl->next = NULL;
+ *ll = cl;
+ ll = &cl->next;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
+{
+ size_t size;
+ ngx_buf_t *in;
+
+ in = ctx->in->buf;
+
+ if (in->file == NULL || !in->file->directio) {
+ return NGX_DECLINED;
+ }
+
+ ctx->directio = 1;
+
+ size = (size_t) (in->file_pos - (in->file_pos & ~(ctx->alignment - 1)));
+
+ if (size == 0) {
+
+ if (bsize >= (off_t) ctx->bufs.size) {
+ return NGX_DECLINED;
+ }
+
+ size = (size_t) bsize;
+
+ } else {
+ size = (size_t) ctx->alignment - size;
+
+ if ((off_t) size > bsize) {
+ size = (size_t) bsize;
+ }
+ }
+
+ ctx->buf = ngx_create_temp_buf(ctx->pool, size);
+ if (ctx->buf == NULL) {
+ return NGX_ERROR;
+ }
+
+ /*
+ * we do not set ctx->buf->tag, because we do not want
+ * to reuse the buf via ctx->free list
+ */
+
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+ ctx->unaligned = 1;
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize)
+{
+ size_t size;
+ ngx_buf_t *b, *in;
+ ngx_uint_t recycled;
+
+ in = ctx->in->buf;
+ size = ctx->bufs.size;
+ recycled = 1;
+
+ if (in->last_in_chain) {
+
+ if (bsize < (off_t) size) {
+
+ /*
+ * allocate a small temp buf for a small last buf
+ * or its small last part
+ */
+
+ size = (size_t) bsize;
+ recycled = 0;
+
+ } else if (!ctx->directio
+ && ctx->bufs.num == 1
+ && (bsize < (off_t) (size + size / 4)))
+ {
+ /*
+ * allocate a temp buf that equals to a last buf,
+ * if there is no directio, the last buf size is lesser
+ * than 1.25 of bufs.size and the temp buf is single
+ */
+
+ size = (size_t) bsize;
+ recycled = 0;
+ }
+ }
+
+ b = ngx_calloc_buf(ctx->pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (ctx->directio) {
+
+ /*
+ * allocate block aligned to a disk sector size to enable
+ * userland buffer direct usage conjunctly with directio
+ */
+
+ b->start = ngx_pmemalign(ctx->pool, size, (size_t) ctx->alignment);
+ if (b->start == NULL) {
+ return NGX_ERROR;
+ }
+
+ } else {
+ b->start = ngx_palloc(ctx->pool, size);
+ if (b->start == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+ b->end = b->last + size;
+ b->temporary = 1;
+ b->tag = ctx->tag;
+ b->recycled = recycled;
+
+ ctx->buf = b;
+ ctx->allocated++;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx)
+{
+ off_t size;
+ ssize_t n;
+ ngx_buf_t *src, *dst;
+ ngx_uint_t sendfile;
+
+ src = ctx->in->buf;
+ dst = ctx->buf;
+
+ size = ngx_buf_size(src);
+ size = ngx_min(size, dst->end - dst->pos);
+
+ sendfile = ctx->sendfile && !ctx->directio;
+
+#if (NGX_SENDFILE_LIMIT)
+
+ if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) {
+ sendfile = 0;
+ }
+
+#endif
+
+ if (ngx_buf_in_memory(src)) {
+ ngx_memcpy(dst->pos, src->pos, (size_t) size);
+ src->pos += (size_t) size;
+ dst->last += (size_t) size;
+
+ if (src->in_file) {
+
+ if (sendfile) {
+ dst->in_file = 1;
+ dst->file = src->file;
+ dst->file_pos = src->file_pos;
+ dst->file_last = src->file_pos + size;
+
+ } else {
+ dst->in_file = 0;
+ }
+
+ src->file_pos += size;
+
+ } else {
+ dst->in_file = 0;
+ }
+
+ if (src->pos == src->last) {
+ dst->flush = src->flush;
+ dst->last_buf = src->last_buf;
+ dst->last_in_chain = src->last_in_chain;
+ }
+
+ } else {
+
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+
+ if (ctx->unaligned) {
+ if (ngx_directio_off(src->file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
+ ngx_directio_off_n " \"%s\" failed",
+ src->file->name.data);
+ }
+ }
+
+#endif
+
+#if (NGX_HAVE_FILE_AIO)
+ if (ctx->aio_handler) {
+ n = ngx_file_aio_read(src->file, dst->pos, (size_t) size,
+ src->file_pos, ctx->pool);
+ if (n == NGX_AGAIN) {
+ ctx->aio_handler(ctx, src->file);
+ return NGX_AGAIN;
+ }
+
+ } else
+#endif
+#if (NGX_THREADS)
+ if (ctx->thread_handler) {
+ src->file->thread_task = ctx->thread_task;
+ src->file->thread_handler = ctx->thread_handler;
+ src->file->thread_ctx = ctx->filter_ctx;
+
+ n = ngx_thread_read(src->file, dst->pos, (size_t) size,
+ src->file_pos, ctx->pool);
+ if (n == NGX_AGAIN) {
+ ctx->thread_task = src->file->thread_task;
+ return NGX_AGAIN;
+ }
+
+ } else
+#endif
+ {
+ n = ngx_read_file(src->file, dst->pos, (size_t) size,
+ src->file_pos);
+ }
+
+#if (NGX_HAVE_ALIGNED_DIRECTIO)
+
+ if (ctx->unaligned) {
+ ngx_err_t err;
+
+ err = ngx_errno;
+
+ if (ngx_directio_on(src->file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno,
+ ngx_directio_on_n " \"%s\" failed",
+ src->file->name.data);
+ }
+
+ ngx_set_errno(err);
+
+ ctx->unaligned = 0;
+ }
+
+#endif
+
+ if (n == NGX_ERROR) {
+ return (ngx_int_t) n;
+ }
+
+ if (n != size) {
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ ngx_read_file_n " read only %z of %O from \"%s\"",
+ n, size, src->file->name.data);
+ return NGX_ERROR;
+ }
+
+ dst->last += n;
+
+ if (sendfile) {
+ dst->in_file = 1;
+ dst->file = src->file;
+ dst->file_pos = src->file_pos;
+ dst->file_last = src->file_pos + n;
+
+ } else {
+ dst->in_file = 0;
+ }
+
+ src->file_pos += n;
+
+ if (src->file_pos == src->file_last) {
+ dst->flush = src->flush;
+ dst->last_buf = src->last_buf;
+ dst->last_in_chain = src->last_in_chain;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_chain_writer(void *data, ngx_chain_t *in)
+{
+ ngx_chain_writer_ctx_t *ctx = data;
+
+ off_t size;
+ ngx_chain_t *cl, *ln, *chain;
+ ngx_connection_t *c;
+
+ c = ctx->connection;
+
+ for (size = 0; in; in = in->next) {
+
+#if 1
+ if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) {
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ "zero size buf in chain writer "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ in->buf->temporary,
+ in->buf->recycled,
+ in->buf->in_file,
+ in->buf->start,
+ in->buf->pos,
+ in->buf->last,
+ in->buf->file,
+ in->buf->file_pos,
+ in->buf->file_last);
+
+ ngx_debug_point();
+
+ continue;
+ }
+#endif
+
+ size += ngx_buf_size(in->buf);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "chain writer buf fl:%d s:%uO",
+ in->buf->flush, ngx_buf_size(in->buf));
+
+ cl = ngx_alloc_chain_link(ctx->pool);
+ if (cl == NULL) {
+ return NGX_ERROR;
+ }
+
+ cl->buf = in->buf;
+ cl->next = NULL;
+ *ctx->last = cl;
+ ctx->last = &cl->next;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "chain writer in: %p", ctx->out);
+
+ for (cl = ctx->out; cl; cl = cl->next) {
+
+#if 1
+ if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) {
+
+ ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
+ "zero size buf in chain writer "
+ "t:%d r:%d f:%d %p %p-%p %p %O-%O",
+ cl->buf->temporary,
+ cl->buf->recycled,
+ cl->buf->in_file,
+ cl->buf->start,
+ cl->buf->pos,
+ cl->buf->last,
+ cl->buf->file,
+ cl->buf->file_pos,
+ cl->buf->file_last);
+
+ ngx_debug_point();
+
+ continue;
+ }
+#endif
+
+ size += ngx_buf_size(cl->buf);
+ }
+
+ if (size == 0 && !c->buffered) {
+ return NGX_OK;
+ }
+
+ chain = c->send_chain(c, ctx->out, ctx->limit);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "chain writer out: %p", chain);
+
+ if (chain == NGX_CHAIN_ERROR) {
+ return NGX_ERROR;
+ }
+
+ for (cl = ctx->out; cl && cl != chain; /* void */) {
+ ln = cl;
+ cl = cl->next;
+ ngx_free_chain(ctx->pool, ln);
+ }
+
+ ctx->out = chain;
+
+ if (ctx->out == NULL) {
+ ctx->last = &ctx->out;
+
+ if (!c->buffered) {
+ return NGX_OK;
+ }
+ }
+
+ return NGX_AGAIN;
+}
diff --git a/app/nginx/src/core/ngx_palloc.c b/app/nginx/src/core/ngx_palloc.c
new file mode 100644
index 0000000..d3044ac
--- /dev/null
+++ b/app/nginx/src/core/ngx_palloc.c
@@ -0,0 +1,430 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size,
+ ngx_uint_t align);
+static void *ngx_palloc_block(ngx_pool_t *pool, size_t size);
+static void *ngx_palloc_large(ngx_pool_t *pool, size_t size);
+
+
+ngx_pool_t *
+ngx_create_pool(size_t size, ngx_log_t *log)
+{
+ ngx_pool_t *p;
+
+ p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
+ if (p == NULL) {
+ return NULL;
+ }
+
+ p->d.last = (u_char *) p + sizeof(ngx_pool_t);
+ p->d.end = (u_char *) p + size;
+ p->d.next = NULL;
+ p->d.failed = 0;
+
+ size = size - sizeof(ngx_pool_t);
+ p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
+
+ p->current = p;
+ p->chain = NULL;
+ p->large = NULL;
+ p->cleanup = NULL;
+ p->log = log;
+
+ return p;
+}
+
+
+void
+ngx_destroy_pool(ngx_pool_t *pool)
+{
+ ngx_pool_t *p, *n;
+ ngx_pool_large_t *l;
+ ngx_pool_cleanup_t *c;
+
+ for (c = pool->cleanup; c; c = c->next) {
+ if (c->handler) {
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
+ "run cleanup: %p", c);
+ c->handler(c->data);
+ }
+ }
+
+#if (NGX_DEBUG)
+
+ /*
+ * we could allocate the pool->log from this pool
+ * so we cannot use this log while free()ing the pool
+ */
+
+ for (l = pool->large; l; l = l->next) {
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
+ }
+
+ for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
+ ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
+ "free: %p, unused: %uz", p, p->d.end - p->d.last);
+
+ if (n == NULL) {
+ break;
+ }
+ }
+
+#endif
+
+ for (l = pool->large; l; l = l->next) {
+ if (l->alloc) {
+ ngx_free(l->alloc);
+ }
+ }
+
+ for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
+ ngx_free(p);
+
+ if (n == NULL) {
+ break;
+ }
+ }
+}
+
+
+void
+ngx_reset_pool(ngx_pool_t *pool)
+{
+ ngx_pool_t *p;
+ ngx_pool_large_t *l;
+
+ for (l = pool->large; l; l = l->next) {
+ if (l->alloc) {
+ ngx_free(l->alloc);
+ }
+ }
+
+ for (p = pool; p; p = p->d.next) {
+ p->d.last = (u_char *) p + sizeof(ngx_pool_t);
+ p->d.failed = 0;
+ }
+
+ pool->current = pool;
+ pool->chain = NULL;
+ pool->large = NULL;
+}
+
+
+void *
+ngx_palloc(ngx_pool_t *pool, size_t size)
+{
+#if !(NGX_DEBUG_PALLOC)
+ if (size <= pool->max) {
+ return ngx_palloc_small(pool, size, 1);
+ }
+#endif
+
+ return ngx_palloc_large(pool, size);
+}
+
+
+void *
+ngx_pnalloc(ngx_pool_t *pool, size_t size)
+{
+#if !(NGX_DEBUG_PALLOC)
+ if (size <= pool->max) {
+ return ngx_palloc_small(pool, size, 0);
+ }
+#endif
+
+ return ngx_palloc_large(pool, size);
+}
+
+
+static ngx_inline void *
+ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
+{
+ u_char *m;
+ ngx_pool_t *p;
+
+ p = pool->current;
+
+ do {
+ m = p->d.last;
+
+ if (align) {
+ m = ngx_align_ptr(m, NGX_ALIGNMENT);
+ }
+
+ if ((size_t) (p->d.end - m) >= size) {
+ p->d.last = m + size;
+
+ return m;
+ }
+
+ p = p->d.next;
+
+ } while (p);
+
+ return ngx_palloc_block(pool, size);
+}
+
+
+static void *
+ngx_palloc_block(ngx_pool_t *pool, size_t size)
+{
+ u_char *m;
+ size_t psize;
+ ngx_pool_t *p, *new;
+
+ psize = (size_t) (pool->d.end - (u_char *) pool);
+
+ m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
+ if (m == NULL) {
+ return NULL;
+ }
+
+ new = (ngx_pool_t *) m;
+
+ new->d.end = m + psize;
+ new->d.next = NULL;
+ new->d.failed = 0;
+
+ m += sizeof(ngx_pool_data_t);
+ m = ngx_align_ptr(m, NGX_ALIGNMENT);
+ new->d.last = m + size;
+
+ for (p = pool->current; p->d.next; p = p->d.next) {
+ if (p->d.failed++ > 4) {
+ pool->current = p->d.next;
+ }
+ }
+
+ p->d.next = new;
+
+ return m;
+}
+
+
+static void *
+ngx_palloc_large(ngx_pool_t *pool, size_t size)
+{
+ void *p;
+ ngx_uint_t n;
+ ngx_pool_large_t *large;
+
+ p = ngx_alloc(size, pool->log);
+ if (p == NULL) {
+ return NULL;
+ }
+
+ n = 0;
+
+ for (large = pool->large; large; large = large->next) {
+ if (large->alloc == NULL) {
+ large->alloc = p;
+ return p;
+ }
+
+ if (n++ > 3) {
+ break;
+ }
+ }
+
+ large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
+ if (large == NULL) {
+ ngx_free(p);
+ return NULL;
+ }
+
+ large->alloc = p;
+ large->next = pool->large;
+ pool->large = large;
+
+ return p;
+}
+
+
+void *
+ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
+{
+ void *p;
+ ngx_pool_large_t *large;
+
+ p = ngx_memalign(alignment, size, pool->log);
+ if (p == NULL) {
+ return NULL;
+ }
+
+ large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
+ if (large == NULL) {
+ ngx_free(p);
+ return NULL;
+ }
+
+ large->alloc = p;
+ large->next = pool->large;
+ pool->large = large;
+
+ return p;
+}
+
+
+ngx_int_t
+ngx_pfree(ngx_pool_t *pool, void *p)
+{
+ ngx_pool_large_t *l;
+
+ for (l = pool->large; l; l = l->next) {
+ if (p == l->alloc) {
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
+ "free: %p", l->alloc);
+ ngx_free(l->alloc);
+ l->alloc = NULL;
+
+ return NGX_OK;
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+
+void *
+ngx_pcalloc(ngx_pool_t *pool, size_t size)
+{
+ void *p;
+
+ p = ngx_palloc(pool, size);
+ if (p) {
+ ngx_memzero(p, size);
+ }
+
+ return p;
+}
+
+
+ngx_pool_cleanup_t *
+ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
+{
+ ngx_pool_cleanup_t *c;
+
+ c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
+ if (c == NULL) {
+ return NULL;
+ }
+
+ if (size) {
+ c->data = ngx_palloc(p, size);
+ if (c->data == NULL) {
+ return NULL;
+ }
+
+ } else {
+ c->data = NULL;
+ }
+
+ c->handler = NULL;
+ c->next = p->cleanup;
+
+ p->cleanup = c;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
+
+ return c;
+}
+
+
+void
+ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
+{
+ ngx_pool_cleanup_t *c;
+ ngx_pool_cleanup_file_t *cf;
+
+ for (c = p->cleanup; c; c = c->next) {
+ if (c->handler == ngx_pool_cleanup_file) {
+
+ cf = c->data;
+
+ if (cf->fd == fd) {
+ c->handler(cf);
+ c->handler = NULL;
+ return;
+ }
+ }
+ }
+}
+
+
+void
+ngx_pool_cleanup_file(void *data)
+{
+ ngx_pool_cleanup_file_t *c = data;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d",
+ c->fd);
+
+ if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", c->name);
+ }
+}
+
+
+void
+ngx_pool_delete_file(void *data)
+{
+ ngx_pool_cleanup_file_t *c = data;
+
+ ngx_err_t err;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, c->log, 0, "file cleanup: fd:%d %s",
+ c->fd, c->name);
+
+ if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+
+ if (err != NGX_ENOENT) {
+ ngx_log_error(NGX_LOG_CRIT, c->log, err,
+ ngx_delete_file_n " \"%s\" failed", c->name);
+ }
+ }
+
+ if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", c->name);
+ }
+}
+
+
+#if 0
+
+static void *
+ngx_get_cached_block(size_t size)
+{
+ void *p;
+ ngx_cached_block_slot_t *slot;
+
+ if (ngx_cycle->cache == NULL) {
+ return NULL;
+ }
+
+ slot = &ngx_cycle->cache[(size + ngx_pagesize - 1) / ngx_pagesize];
+
+ slot->tries++;
+
+ if (slot->number) {
+ p = slot->block;
+ slot->block = slot->block->next;
+ slot->number--;
+ return p;
+ }
+
+ return NULL;
+}
+
+#endif
diff --git a/app/nginx/src/core/ngx_palloc.h b/app/nginx/src/core/ngx_palloc.h
new file mode 100644
index 0000000..d652829
--- /dev/null
+++ b/app/nginx/src/core/ngx_palloc.h
@@ -0,0 +1,95 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PALLOC_H_INCLUDED_
+#define _NGX_PALLOC_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.
+ * On Windows NT it decreases a number of locked pages in a kernel.
+ */
+#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)
+
+#define NGX_DEFAULT_POOL_SIZE (16 * 1024)
+
+#define NGX_POOL_ALIGNMENT 16
+#define NGX_MIN_POOL_SIZE \
+ ngx_align((sizeof(ngx_pool_t) + 2 * sizeof(ngx_pool_large_t)), \
+ NGX_POOL_ALIGNMENT)
+
+
+typedef void (*ngx_pool_cleanup_pt)(void *data);
+
+typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
+
+struct ngx_pool_cleanup_s {
+ ngx_pool_cleanup_pt handler;
+ void *data;
+ ngx_pool_cleanup_t *next;
+};
+
+
+typedef struct ngx_pool_large_s ngx_pool_large_t;
+
+struct ngx_pool_large_s {
+ ngx_pool_large_t *next;
+ void *alloc;
+};
+
+
+typedef struct {
+ u_char *last;
+ u_char *end;
+ ngx_pool_t *next;
+ ngx_uint_t failed;
+} ngx_pool_data_t;
+
+
+struct ngx_pool_s {
+ ngx_pool_data_t d;
+ size_t max;
+ ngx_pool_t *current;
+ ngx_chain_t *chain;
+ ngx_pool_large_t *large;
+ ngx_pool_cleanup_t *cleanup;
+ ngx_log_t *log;
+};
+
+
+typedef struct {
+ ngx_fd_t fd;
+ u_char *name;
+ ngx_log_t *log;
+} ngx_pool_cleanup_file_t;
+
+
+void *ngx_alloc(size_t size, ngx_log_t *log);
+void *ngx_calloc(size_t size, ngx_log_t *log);
+
+ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
+void ngx_destroy_pool(ngx_pool_t *pool);
+void ngx_reset_pool(ngx_pool_t *pool);
+
+void *ngx_palloc(ngx_pool_t *pool, size_t size);
+void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
+void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
+void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
+ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
+
+
+ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
+void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
+void ngx_pool_cleanup_file(void *data);
+void ngx_pool_delete_file(void *data);
+
+
+#endif /* _NGX_PALLOC_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_parse.c b/app/nginx/src/core/ngx_parse.c
new file mode 100644
index 0000000..d35e60f
--- /dev/null
+++ b/app/nginx/src/core/ngx_parse.c
@@ -0,0 +1,283 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ssize_t
+ngx_parse_size(ngx_str_t *line)
+{
+ u_char unit;
+ size_t len;
+ ssize_t size, scale, max;
+
+ len = line->len;
+
+ if (len == 0) {
+ return NGX_ERROR;
+ }
+
+ unit = line->data[len - 1];
+
+ switch (unit) {
+ case 'K':
+ case 'k':
+ len--;
+ max = NGX_MAX_SIZE_T_VALUE / 1024;
+ scale = 1024;
+ break;
+
+ case 'M':
+ case 'm':
+ len--;
+ max = NGX_MAX_SIZE_T_VALUE / (1024 * 1024);
+ scale = 1024 * 1024;
+ break;
+
+ default:
+ max = NGX_MAX_SIZE_T_VALUE;
+ scale = 1;
+ }
+
+ size = ngx_atosz(line->data, len);
+ if (size == NGX_ERROR || size > max) {
+ return NGX_ERROR;
+ }
+
+ size *= scale;
+
+ return size;
+}
+
+
+off_t
+ngx_parse_offset(ngx_str_t *line)
+{
+ u_char unit;
+ off_t offset, scale, max;
+ size_t len;
+
+ len = line->len;
+
+ if (len == 0) {
+ return NGX_ERROR;
+ }
+
+ unit = line->data[len - 1];
+
+ switch (unit) {
+ case 'K':
+ case 'k':
+ len--;
+ max = NGX_MAX_OFF_T_VALUE / 1024;
+ scale = 1024;
+ break;
+
+ case 'M':
+ case 'm':
+ len--;
+ max = NGX_MAX_OFF_T_VALUE / (1024 * 1024);
+ scale = 1024 * 1024;
+ break;
+
+ case 'G':
+ case 'g':
+ len--;
+ max = NGX_MAX_OFF_T_VALUE / (1024 * 1024 * 1024);
+ scale = 1024 * 1024 * 1024;
+ break;
+
+ default:
+ max = NGX_MAX_OFF_T_VALUE;
+ scale = 1;
+ }
+
+ offset = ngx_atoof(line->data, len);
+ if (offset == NGX_ERROR || offset > max) {
+ return NGX_ERROR;
+ }
+
+ offset *= scale;
+
+ return offset;
+}
+
+
+ngx_int_t
+ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec)
+{
+ u_char *p, *last;
+ ngx_int_t value, total, scale;
+ ngx_int_t max, cutoff, cutlim;
+ ngx_uint_t valid;
+ enum {
+ st_start = 0,
+ st_year,
+ st_month,
+ st_week,
+ st_day,
+ st_hour,
+ st_min,
+ st_sec,
+ st_msec,
+ st_last
+ } step;
+
+ valid = 0;
+ value = 0;
+ total = 0;
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
+ step = is_sec ? st_start : st_month;
+
+ p = line->data;
+ last = p + line->len;
+
+ while (p < last) {
+
+ if (*p >= '0' && *p <= '9') {
+ if (value >= cutoff && (value > cutoff || *p - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*p++ - '0');
+ valid = 1;
+ continue;
+ }
+
+ switch (*p++) {
+
+ case 'y':
+ if (step > st_start) {
+ return NGX_ERROR;
+ }
+ step = st_year;
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 365);
+ scale = 60 * 60 * 24 * 365;
+ break;
+
+ case 'M':
+ if (step >= st_month) {
+ return NGX_ERROR;
+ }
+ step = st_month;
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 30);
+ scale = 60 * 60 * 24 * 30;
+ break;
+
+ case 'w':
+ if (step >= st_week) {
+ return NGX_ERROR;
+ }
+ step = st_week;
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24 * 7);
+ scale = 60 * 60 * 24 * 7;
+ break;
+
+ case 'd':
+ if (step >= st_day) {
+ return NGX_ERROR;
+ }
+ step = st_day;
+ max = NGX_MAX_INT_T_VALUE / (60 * 60 * 24);
+ scale = 60 * 60 * 24;
+ break;
+
+ case 'h':
+ if (step >= st_hour) {
+ return NGX_ERROR;
+ }
+ step = st_hour;
+ max = NGX_MAX_INT_T_VALUE / (60 * 60);
+ scale = 60 * 60;
+ break;
+
+ case 'm':
+ if (p < last && *p == 's') {
+ if (is_sec || step >= st_msec) {
+ return NGX_ERROR;
+ }
+ p++;
+ step = st_msec;
+ max = NGX_MAX_INT_T_VALUE;
+ scale = 1;
+ break;
+ }
+
+ if (step >= st_min) {
+ return NGX_ERROR;
+ }
+ step = st_min;
+ max = NGX_MAX_INT_T_VALUE / 60;
+ scale = 60;
+ break;
+
+ case 's':
+ if (step >= st_sec) {
+ return NGX_ERROR;
+ }
+ step = st_sec;
+ max = NGX_MAX_INT_T_VALUE;
+ scale = 1;
+ break;
+
+ case ' ':
+ if (step >= st_sec) {
+ return NGX_ERROR;
+ }
+ step = st_last;
+ max = NGX_MAX_INT_T_VALUE;
+ scale = 1;
+ break;
+
+ default:
+ return NGX_ERROR;
+ }
+
+ if (step != st_msec && !is_sec) {
+ scale *= 1000;
+ max /= 1000;
+ }
+
+ if (value > max) {
+ return NGX_ERROR;
+ }
+
+ value *= scale;
+
+ if (total > NGX_MAX_INT_T_VALUE - value) {
+ return NGX_ERROR;
+ }
+
+ total += value;
+
+ value = 0;
+
+ while (p < last && *p == ' ') {
+ p++;
+ }
+ }
+
+ if (!valid) {
+ return NGX_ERROR;
+ }
+
+ if (!is_sec) {
+ if (value > NGX_MAX_INT_T_VALUE / 1000) {
+ return NGX_ERROR;
+ }
+
+ value *= 1000;
+ }
+
+ if (total > NGX_MAX_INT_T_VALUE - value) {
+ return NGX_ERROR;
+ }
+
+ return total + value;
+}
diff --git a/app/nginx/src/core/ngx_parse.h b/app/nginx/src/core/ngx_parse.h
new file mode 100644
index 0000000..ec093b5
--- /dev/null
+++ b/app/nginx/src/core/ngx_parse.h
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PARSE_H_INCLUDED_
+#define _NGX_PARSE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+ssize_t ngx_parse_size(ngx_str_t *line);
+off_t ngx_parse_offset(ngx_str_t *line);
+ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec);
+
+
+#endif /* _NGX_PARSE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_parse_time.c b/app/nginx/src/core/ngx_parse_time.c
new file mode 100644
index 0000000..13afde3
--- /dev/null
+++ b/app/nginx/src/core/ngx_parse_time.c
@@ -0,0 +1,276 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static ngx_uint_t mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+time_t
+ngx_parse_http_time(u_char *value, size_t len)
+{
+ u_char *p, *end;
+ ngx_int_t month;
+ ngx_uint_t day, year, hour, min, sec;
+ uint64_t time;
+ enum {
+ no = 0,
+ rfc822, /* Tue, 10 Nov 2002 23:50:13 */
+ rfc850, /* Tuesday, 10-Dec-02 23:50:13 */
+ isoc /* Tue Dec 10 23:50:13 2002 */
+ } fmt;
+
+ fmt = 0;
+ end = value + len;
+
+#if (NGX_SUPPRESS_WARN)
+ day = 32;
+ year = 2038;
+#endif
+
+ for (p = value; p < end; p++) {
+ if (*p == ',') {
+ break;
+ }
+
+ if (*p == ' ') {
+ fmt = isoc;
+ break;
+ }
+ }
+
+ for (p++; p < end; p++)
+ if (*p != ' ') {
+ break;
+ }
+
+ if (end - p < 18) {
+ return NGX_ERROR;
+ }
+
+ if (fmt != isoc) {
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
+ return NGX_ERROR;
+ }
+
+ day = (*p - '0') * 10 + *(p + 1) - '0';
+ p += 2;
+
+ if (*p == ' ') {
+ if (end - p < 18) {
+ return NGX_ERROR;
+ }
+ fmt = rfc822;
+
+ } else if (*p == '-') {
+ fmt = rfc850;
+
+ } else {
+ return NGX_ERROR;
+ }
+
+ p++;
+ }
+
+ switch (*p) {
+
+ case 'J':
+ month = *(p + 1) == 'a' ? 0 : *(p + 2) == 'n' ? 5 : 6;
+ break;
+
+ case 'F':
+ month = 1;
+ break;
+
+ case 'M':
+ month = *(p + 2) == 'r' ? 2 : 4;
+ break;
+
+ case 'A':
+ month = *(p + 1) == 'p' ? 3 : 7;
+ break;
+
+ case 'S':
+ month = 8;
+ break;
+
+ case 'O':
+ month = 9;
+ break;
+
+ case 'N':
+ month = 10;
+ break;
+
+ case 'D':
+ month = 11;
+ break;
+
+ default:
+ return NGX_ERROR;
+ }
+
+ p += 3;
+
+ if ((fmt == rfc822 && *p != ' ') || (fmt == rfc850 && *p != '-')) {
+ return NGX_ERROR;
+ }
+
+ p++;
+
+ if (fmt == rfc822) {
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
+ || *(p + 2) < '0' || *(p + 2) > '9'
+ || *(p + 3) < '0' || *(p + 3) > '9')
+ {
+ return NGX_ERROR;
+ }
+
+ year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
+ + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
+ p += 4;
+
+ } else if (fmt == rfc850) {
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
+ return NGX_ERROR;
+ }
+
+ year = (*p - '0') * 10 + *(p + 1) - '0';
+ year += (year < 70) ? 2000 : 1900;
+ p += 2;
+ }
+
+ if (fmt == isoc) {
+ if (*p == ' ') {
+ p++;
+ }
+
+ if (*p < '0' || *p > '9') {
+ return NGX_ERROR;
+ }
+
+ day = *p++ - '0';
+
+ if (*p != ' ') {
+ if (*p < '0' || *p > '9') {
+ return NGX_ERROR;
+ }
+
+ day = day * 10 + *p++ - '0';
+ }
+
+ if (end - p < 14) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (*p++ != ' ') {
+ return NGX_ERROR;
+ }
+
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
+ return NGX_ERROR;
+ }
+
+ hour = (*p - '0') * 10 + *(p + 1) - '0';
+ p += 2;
+
+ if (*p++ != ':') {
+ return NGX_ERROR;
+ }
+
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
+ return NGX_ERROR;
+ }
+
+ min = (*p - '0') * 10 + *(p + 1) - '0';
+ p += 2;
+
+ if (*p++ != ':') {
+ return NGX_ERROR;
+ }
+
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') {
+ return NGX_ERROR;
+ }
+
+ sec = (*p - '0') * 10 + *(p + 1) - '0';
+
+ if (fmt == isoc) {
+ p += 2;
+
+ if (*p++ != ' ') {
+ return NGX_ERROR;
+ }
+
+ if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9'
+ || *(p + 2) < '0' || *(p + 2) > '9'
+ || *(p + 3) < '0' || *(p + 3) > '9')
+ {
+ return NGX_ERROR;
+ }
+
+ year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100
+ + (*(p + 2) - '0') * 10 + *(p + 3) - '0';
+ }
+
+ if (hour > 23 || min > 59 || sec > 59) {
+ return NGX_ERROR;
+ }
+
+ if (day == 29 && month == 1) {
+ if ((year & 3) || ((year % 100 == 0) && (year % 400) != 0)) {
+ return NGX_ERROR;
+ }
+
+ } else if (day > mday[month]) {
+ return NGX_ERROR;
+ }
+
+ /*
+ * shift new year to March 1 and start months from 1 (not 0),
+ * it is needed for Gauss' formula
+ */
+
+ if (--month <= 0) {
+ month += 12;
+ year -= 1;
+ }
+
+ /* Gauss' formula for Gregorian days since March 1, 1 BC */
+
+ time = (uint64_t) (
+ /* days in years including leap years since March 1, 1 BC */
+
+ 365 * year + year / 4 - year / 100 + year / 400
+
+ /* days before the month */
+
+ + 367 * month / 12 - 30
+
+ /* days before the day */
+
+ + day - 1
+
+ /*
+ * 719527 days were between March 1, 1 BC and March 1, 1970,
+ * 31 and 28 days were in January and February 1970
+ */
+
+ - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec;
+
+#if (NGX_TIME_T_SIZE <= 4)
+
+ if (time > 0x7fffffff) {
+ return NGX_ERROR;
+ }
+
+#endif
+
+ return (time_t) time;
+}
diff --git a/app/nginx/src/core/ngx_parse_time.h b/app/nginx/src/core/ngx_parse_time.h
new file mode 100644
index 0000000..aa542eb
--- /dev/null
+++ b/app/nginx/src/core/ngx_parse_time.h
@@ -0,0 +1,22 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PARSE_TIME_H_INCLUDED_
+#define _NGX_PARSE_TIME_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+time_t ngx_parse_http_time(u_char *value, size_t len);
+
+/* compatibility */
+#define ngx_http_parse_time(value, len) ngx_parse_http_time(value, len)
+
+
+#endif /* _NGX_PARSE_TIME_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_proxy_protocol.c b/app/nginx/src/core/ngx_proxy_protocol.c
new file mode 100644
index 0000000..523ec35
--- /dev/null
+++ b/app/nginx/src/core/ngx_proxy_protocol.c
@@ -0,0 +1,168 @@
+
+/*
+ * Copyright (C) Roman Arutyunyan
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+u_char *
+ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
+{
+ size_t len;
+ u_char ch, *p, *addr, *port;
+ ngx_int_t n;
+
+ p = buf;
+ len = last - buf;
+
+ if (len < 8 || ngx_strncmp(p, "PROXY ", 6) != 0) {
+ goto invalid;
+ }
+
+ p += 6;
+ len -= 6;
+
+ if (len >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol unknown protocol");
+ p += 7;
+ goto skip;
+ }
+
+ if (len < 5 || ngx_strncmp(p, "TCP", 3) != 0
+ || (p[3] != '4' && p[3] != '6') || p[4] != ' ')
+ {
+ goto invalid;
+ }
+
+ p += 5;
+ addr = p;
+
+ for ( ;; ) {
+ if (p == last) {
+ goto invalid;
+ }
+
+ ch = *p++;
+
+ if (ch == ' ') {
+ break;
+ }
+
+ if (ch != ':' && ch != '.'
+ && (ch < 'a' || ch > 'f')
+ && (ch < 'A' || ch > 'F')
+ && (ch < '0' || ch > '9'))
+ {
+ goto invalid;
+ }
+ }
+
+ len = p - addr - 1;
+ c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
+
+ if (c->proxy_protocol_addr.data == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(c->proxy_protocol_addr.data, addr, len);
+ c->proxy_protocol_addr.len = len;
+
+ for ( ;; ) {
+ if (p == last) {
+ goto invalid;
+ }
+
+ if (*p++ == ' ') {
+ break;
+ }
+ }
+
+ port = p;
+
+ for ( ;; ) {
+ if (p == last) {
+ goto invalid;
+ }
+
+ if (*p++ == ' ') {
+ break;
+ }
+ }
+
+ len = p - port - 1;
+
+ n = ngx_atoi(port, len);
+
+ if (n < 0 || n > 65535) {
+ goto invalid;
+ }
+
+ c->proxy_protocol_port = (in_port_t) n;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
+ "PROXY protocol address: %V %i", &c->proxy_protocol_addr, n);
+
+skip:
+
+ for ( /* void */ ; p < last - 1; p++) {
+ if (p[0] == CR && p[1] == LF) {
+ return p + 2;
+ }
+ }
+
+invalid:
+
+ ngx_log_error(NGX_LOG_ERR, c->log, 0,
+ "broken header: \"%*s\"", (size_t) (last - buf), buf);
+
+ return NULL;
+}
+
+
+u_char *
+ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
+{
+ ngx_uint_t port, lport;
+
+ if (last - buf < NGX_PROXY_PROTOCOL_MAX_HEADER) {
+ return NULL;
+ }
+
+ if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
+ return NULL;
+ }
+
+ switch (c->sockaddr->sa_family) {
+
+ case AF_INET:
+ buf = ngx_cpymem(buf, "PROXY TCP4 ", sizeof("PROXY TCP4 ") - 1);
+ break;
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ buf = ngx_cpymem(buf, "PROXY TCP6 ", sizeof("PROXY TCP6 ") - 1);
+ break;
+#endif
+
+ default:
+ return ngx_cpymem(buf, "PROXY UNKNOWN" CRLF,
+ sizeof("PROXY UNKNOWN" CRLF) - 1);
+ }
+
+ buf += ngx_sock_ntop(c->sockaddr, c->socklen, buf, last - buf, 0);
+
+ *buf++ = ' ';
+
+ buf += ngx_sock_ntop(c->local_sockaddr, c->local_socklen, buf, last - buf,
+ 0);
+
+ port = ngx_inet_get_port(c->sockaddr);
+ lport = ngx_inet_get_port(c->local_sockaddr);
+
+ return ngx_slprintf(buf, last, " %ui %ui" CRLF, port, lport);
+}
diff --git a/app/nginx/src/core/ngx_proxy_protocol.h b/app/nginx/src/core/ngx_proxy_protocol.h
new file mode 100644
index 0000000..fb848f6
--- /dev/null
+++ b/app/nginx/src/core/ngx_proxy_protocol.h
@@ -0,0 +1,25 @@
+
+/*
+ * Copyright (C) Roman Arutyunyan
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_PROXY_PROTOCOL_H_INCLUDED_
+#define _NGX_PROXY_PROTOCOL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_PROXY_PROTOCOL_MAX_HEADER 107
+
+
+u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
+ u_char *last);
+u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
+ u_char *last);
+
+
+#endif /* _NGX_PROXY_PROTOCOL_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_queue.c b/app/nginx/src/core/ngx_queue.c
new file mode 100644
index 0000000..3cacaf3
--- /dev/null
+++ b/app/nginx/src/core/ngx_queue.c
@@ -0,0 +1,80 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * find the middle queue element if the queue has odd number of elements
+ * or the first element of the queue's second part otherwise
+ */
+
+ngx_queue_t *
+ngx_queue_middle(ngx_queue_t *queue)
+{
+ ngx_queue_t *middle, *next;
+
+ middle = ngx_queue_head(queue);
+
+ if (middle == ngx_queue_last(queue)) {
+ return middle;
+ }
+
+ next = ngx_queue_head(queue);
+
+ for ( ;; ) {
+ middle = ngx_queue_next(middle);
+
+ next = ngx_queue_next(next);
+
+ if (next == ngx_queue_last(queue)) {
+ return middle;
+ }
+
+ next = ngx_queue_next(next);
+
+ if (next == ngx_queue_last(queue)) {
+ return middle;
+ }
+ }
+}
+
+
+/* the stable insertion sort */
+
+void
+ngx_queue_sort(ngx_queue_t *queue,
+ ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *))
+{
+ ngx_queue_t *q, *prev, *next;
+
+ q = ngx_queue_head(queue);
+
+ if (q == ngx_queue_last(queue)) {
+ return;
+ }
+
+ for (q = ngx_queue_next(q); q != ngx_queue_sentinel(queue); q = next) {
+
+ prev = ngx_queue_prev(q);
+ next = ngx_queue_next(q);
+
+ ngx_queue_remove(q);
+
+ do {
+ if (cmp(prev, q) <= 0) {
+ break;
+ }
+
+ prev = ngx_queue_prev(prev);
+
+ } while (prev != ngx_queue_sentinel(queue));
+
+ ngx_queue_insert_after(prev, q);
+ }
+}
diff --git a/app/nginx/src/core/ngx_queue.h b/app/nginx/src/core/ngx_queue.h
new file mode 100644
index 0000000..038bf12
--- /dev/null
+++ b/app/nginx/src/core/ngx_queue.h
@@ -0,0 +1,112 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#ifndef _NGX_QUEUE_H_INCLUDED_
+#define _NGX_QUEUE_H_INCLUDED_
+
+
+typedef struct ngx_queue_s ngx_queue_t;
+
+struct ngx_queue_s {
+ ngx_queue_t *prev;
+ ngx_queue_t *next;
+};
+
+
+#define ngx_queue_init(q) \
+ (q)->prev = q; \
+ (q)->next = q
+
+
+#define ngx_queue_empty(h) \
+ (h == (h)->prev)
+
+
+#define ngx_queue_insert_head(h, x) \
+ (x)->next = (h)->next; \
+ (x)->next->prev = x; \
+ (x)->prev = h; \
+ (h)->next = x
+
+
+#define ngx_queue_insert_after ngx_queue_insert_head
+
+
+#define ngx_queue_insert_tail(h, x) \
+ (x)->prev = (h)->prev; \
+ (x)->prev->next = x; \
+ (x)->next = h; \
+ (h)->prev = x
+
+
+#define ngx_queue_head(h) \
+ (h)->next
+
+
+#define ngx_queue_last(h) \
+ (h)->prev
+
+
+#define ngx_queue_sentinel(h) \
+ (h)
+
+
+#define ngx_queue_next(q) \
+ (q)->next
+
+
+#define ngx_queue_prev(q) \
+ (q)->prev
+
+
+#if (NGX_DEBUG)
+
+#define ngx_queue_remove(x) \
+ (x)->next->prev = (x)->prev; \
+ (x)->prev->next = (x)->next; \
+ (x)->prev = NULL; \
+ (x)->next = NULL
+
+#else
+
+#define ngx_queue_remove(x) \
+ (x)->next->prev = (x)->prev; \
+ (x)->prev->next = (x)->next
+
+#endif
+
+
+#define ngx_queue_split(h, q, n) \
+ (n)->prev = (h)->prev; \
+ (n)->prev->next = n; \
+ (n)->next = q; \
+ (h)->prev = (q)->prev; \
+ (h)->prev->next = h; \
+ (q)->prev = n;
+
+
+#define ngx_queue_add(h, n) \
+ (h)->prev->next = (n)->next; \
+ (n)->next->prev = (h)->prev; \
+ (h)->prev = (n)->prev; \
+ (h)->prev->next = h;
+
+
+#define ngx_queue_data(q, type, link) \
+ (type *) ((u_char *) q - offsetof(type, link))
+
+
+ngx_queue_t *ngx_queue_middle(ngx_queue_t *queue);
+void ngx_queue_sort(ngx_queue_t *queue,
+ ngx_int_t (*cmp)(const ngx_queue_t *, const ngx_queue_t *));
+
+
+#endif /* _NGX_QUEUE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_radix_tree.c b/app/nginx/src/core/ngx_radix_tree.c
new file mode 100644
index 0000000..c1d8737
--- /dev/null
+++ b/app/nginx/src/core/ngx_radix_tree.c
@@ -0,0 +1,488 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree);
+
+
+ngx_radix_tree_t *
+ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
+{
+ uint32_t key, mask, inc;
+ ngx_radix_tree_t *tree;
+
+ tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
+ if (tree == NULL) {
+ return NULL;
+ }
+
+ tree->pool = pool;
+ tree->free = NULL;
+ tree->start = NULL;
+ tree->size = 0;
+
+ tree->root = ngx_radix_alloc(tree);
+ if (tree->root == NULL) {
+ return NULL;
+ }
+
+ tree->root->right = NULL;
+ tree->root->left = NULL;
+ tree->root->parent = NULL;
+ tree->root->value = NGX_RADIX_NO_VALUE;
+
+ if (preallocate == 0) {
+ return tree;
+ }
+
+ /*
+ * Preallocation of first nodes : 0, 1, 00, 01, 10, 11, 000, 001, etc.
+ * increases TLB hits even if for first lookup iterations.
+ * On 32-bit platforms the 7 preallocated bits takes continuous 4K,
+ * 8 - 8K, 9 - 16K, etc. On 64-bit platforms the 6 preallocated bits
+ * takes continuous 4K, 7 - 8K, 8 - 16K, etc. There is no sense to
+ * to preallocate more than one page, because further preallocation
+ * distributes the only bit per page. Instead, a random insertion
+ * may distribute several bits per page.
+ *
+ * Thus, by default we preallocate maximum
+ * 6 bits on amd64 (64-bit platform and 4K pages)
+ * 7 bits on i386 (32-bit platform and 4K pages)
+ * 7 bits on sparc64 in 64-bit mode (8K pages)
+ * 8 bits on sparc64 in 32-bit mode (8K pages)
+ */
+
+ if (preallocate == -1) {
+ switch (ngx_pagesize / sizeof(ngx_radix_node_t)) {
+
+ /* amd64 */
+ case 128:
+ preallocate = 6;
+ break;
+
+ /* i386, sparc64 */
+ case 256:
+ preallocate = 7;
+ break;
+
+ /* sparc64 in 32-bit mode */
+ default:
+ preallocate = 8;
+ }
+ }
+
+ mask = 0;
+ inc = 0x80000000;
+
+ while (preallocate--) {
+
+ key = 0;
+ mask >>= 1;
+ mask |= 0x80000000;
+
+ do {
+ if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
+ != NGX_OK)
+ {
+ return NULL;
+ }
+
+ key += inc;
+
+ } while (key);
+
+ inc >>= 1;
+ }
+
+ return tree;
+}
+
+
+ngx_int_t
+ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
+ uintptr_t value)
+{
+ uint32_t bit;
+ ngx_radix_node_t *node, *next;
+
+ bit = 0x80000000;
+
+ node = tree->root;
+ next = tree->root;
+
+ while (bit & mask) {
+ if (key & bit) {
+ next = node->right;
+
+ } else {
+ next = node->left;
+ }
+
+ if (next == NULL) {
+ break;
+ }
+
+ bit >>= 1;
+ node = next;
+ }
+
+ if (next) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ return NGX_BUSY;
+ }
+
+ node->value = value;
+ return NGX_OK;
+ }
+
+ while (bit & mask) {
+ next = ngx_radix_alloc(tree);
+ if (next == NULL) {
+ return NGX_ERROR;
+ }
+
+ next->right = NULL;
+ next->left = NULL;
+ next->parent = node;
+ next->value = NGX_RADIX_NO_VALUE;
+
+ if (key & bit) {
+ node->right = next;
+
+ } else {
+ node->left = next;
+ }
+
+ bit >>= 1;
+ node = next;
+ }
+
+ node->value = value;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
+{
+ uint32_t bit;
+ ngx_radix_node_t *node;
+
+ bit = 0x80000000;
+ node = tree->root;
+
+ while (node && (bit & mask)) {
+ if (key & bit) {
+ node = node->right;
+
+ } else {
+ node = node->left;
+ }
+
+ bit >>= 1;
+ }
+
+ if (node == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (node->right || node->left) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ node->value = NGX_RADIX_NO_VALUE;
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+ }
+
+ for ( ;; ) {
+ if (node->parent->right == node) {
+ node->parent->right = NULL;
+
+ } else {
+ node->parent->left = NULL;
+ }
+
+ node->right = tree->free;
+ tree->free = node;
+
+ node = node->parent;
+
+ if (node->right || node->left) {
+ break;
+ }
+
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ break;
+ }
+
+ if (node->parent == NULL) {
+ break;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+uintptr_t
+ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
+{
+ uint32_t bit;
+ uintptr_t value;
+ ngx_radix_node_t *node;
+
+ bit = 0x80000000;
+ value = NGX_RADIX_NO_VALUE;
+ node = tree->root;
+
+ while (node) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ value = node->value;
+ }
+
+ if (key & bit) {
+ node = node->right;
+
+ } else {
+ node = node->left;
+ }
+
+ bit >>= 1;
+ }
+
+ return value;
+}
+
+
+#if (NGX_HAVE_INET6)
+
+ngx_int_t
+ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask,
+ uintptr_t value)
+{
+ u_char bit;
+ ngx_uint_t i;
+ ngx_radix_node_t *node, *next;
+
+ i = 0;
+ bit = 0x80;
+
+ node = tree->root;
+ next = tree->root;
+
+ while (bit & mask[i]) {
+ if (key[i] & bit) {
+ next = node->right;
+
+ } else {
+ next = node->left;
+ }
+
+ if (next == NULL) {
+ break;
+ }
+
+ bit >>= 1;
+ node = next;
+
+ if (bit == 0) {
+ if (++i == 16) {
+ break;
+ }
+
+ bit = 0x80;
+ }
+ }
+
+ if (next) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ return NGX_BUSY;
+ }
+
+ node->value = value;
+ return NGX_OK;
+ }
+
+ while (bit & mask[i]) {
+ next = ngx_radix_alloc(tree);
+ if (next == NULL) {
+ return NGX_ERROR;
+ }
+
+ next->right = NULL;
+ next->left = NULL;
+ next->parent = node;
+ next->value = NGX_RADIX_NO_VALUE;
+
+ if (key[i] & bit) {
+ node->right = next;
+
+ } else {
+ node->left = next;
+ }
+
+ bit >>= 1;
+ node = next;
+
+ if (bit == 0) {
+ if (++i == 16) {
+ break;
+ }
+
+ bit = 0x80;
+ }
+ }
+
+ node->value = value;
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask)
+{
+ u_char bit;
+ ngx_uint_t i;
+ ngx_radix_node_t *node;
+
+ i = 0;
+ bit = 0x80;
+ node = tree->root;
+
+ while (node && (bit & mask[i])) {
+ if (key[i] & bit) {
+ node = node->right;
+
+ } else {
+ node = node->left;
+ }
+
+ bit >>= 1;
+
+ if (bit == 0) {
+ if (++i == 16) {
+ break;
+ }
+
+ bit = 0x80;
+ }
+ }
+
+ if (node == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (node->right || node->left) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ node->value = NGX_RADIX_NO_VALUE;
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+ }
+
+ for ( ;; ) {
+ if (node->parent->right == node) {
+ node->parent->right = NULL;
+
+ } else {
+ node->parent->left = NULL;
+ }
+
+ node->right = tree->free;
+ tree->free = node;
+
+ node = node->parent;
+
+ if (node->right || node->left) {
+ break;
+ }
+
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ break;
+ }
+
+ if (node->parent == NULL) {
+ break;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+uintptr_t
+ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key)
+{
+ u_char bit;
+ uintptr_t value;
+ ngx_uint_t i;
+ ngx_radix_node_t *node;
+
+ i = 0;
+ bit = 0x80;
+ value = NGX_RADIX_NO_VALUE;
+ node = tree->root;
+
+ while (node) {
+ if (node->value != NGX_RADIX_NO_VALUE) {
+ value = node->value;
+ }
+
+ if (key[i] & bit) {
+ node = node->right;
+
+ } else {
+ node = node->left;
+ }
+
+ bit >>= 1;
+
+ if (bit == 0) {
+ i++;
+ bit = 0x80;
+ }
+ }
+
+ return value;
+}
+
+#endif
+
+
+static ngx_radix_node_t *
+ngx_radix_alloc(ngx_radix_tree_t *tree)
+{
+ ngx_radix_node_t *p;
+
+ if (tree->free) {
+ p = tree->free;
+ tree->free = tree->free->right;
+ return p;
+ }
+
+ if (tree->size < sizeof(ngx_radix_node_t)) {
+ tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize);
+ if (tree->start == NULL) {
+ return NULL;
+ }
+
+ tree->size = ngx_pagesize;
+ }
+
+ p = (ngx_radix_node_t *) tree->start;
+ tree->start += sizeof(ngx_radix_node_t);
+ tree->size -= sizeof(ngx_radix_node_t);
+
+ return p;
+}
diff --git a/app/nginx/src/core/ngx_radix_tree.h b/app/nginx/src/core/ngx_radix_tree.h
new file mode 100644
index 0000000..4fe06e0
--- /dev/null
+++ b/app/nginx/src/core/ngx_radix_tree.h
@@ -0,0 +1,55 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_RADIX_TREE_H_INCLUDED_
+#define _NGX_RADIX_TREE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_RADIX_NO_VALUE (uintptr_t) -1
+
+typedef struct ngx_radix_node_s ngx_radix_node_t;
+
+struct ngx_radix_node_s {
+ ngx_radix_node_t *right;
+ ngx_radix_node_t *left;
+ ngx_radix_node_t *parent;
+ uintptr_t value;
+};
+
+
+typedef struct {
+ ngx_radix_node_t *root;
+ ngx_pool_t *pool;
+ ngx_radix_node_t *free;
+ char *start;
+ size_t size;
+} ngx_radix_tree_t;
+
+
+ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool,
+ ngx_int_t preallocate);
+
+ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree,
+ uint32_t key, uint32_t mask, uintptr_t value);
+ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree,
+ uint32_t key, uint32_t mask);
+uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key);
+
+#if (NGX_HAVE_INET6)
+ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree,
+ u_char *key, u_char *mask, uintptr_t value);
+ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree,
+ u_char *key, u_char *mask);
+uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key);
+#endif
+
+
+#endif /* _NGX_RADIX_TREE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_rbtree.c b/app/nginx/src/core/ngx_rbtree.c
new file mode 100644
index 0000000..969d549
--- /dev/null
+++ b/app/nginx/src/core/ngx_rbtree.c
@@ -0,0 +1,409 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * The red-black tree code is based on the algorithm described in
+ * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest.
+ */
+
+
+static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root,
+ ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
+static ngx_inline void ngx_rbtree_right_rotate(ngx_rbtree_node_t **root,
+ ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node);
+
+
+void
+ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
+{
+ ngx_rbtree_node_t **root, *temp, *sentinel;
+
+ /* a binary tree insert */
+
+ root = &tree->root;
+ sentinel = tree->sentinel;
+
+ if (*root == sentinel) {
+ node->parent = NULL;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_black(node);
+ *root = node;
+
+ return;
+ }
+
+ tree->insert(*root, node, sentinel);
+
+ /* re-balance tree */
+
+ while (node != *root && ngx_rbt_is_red(node->parent)) {
+
+ if (node->parent == node->parent->parent->left) {
+ temp = node->parent->parent->right;
+
+ if (ngx_rbt_is_red(temp)) {
+ ngx_rbt_black(node->parent);
+ ngx_rbt_black(temp);
+ ngx_rbt_red(node->parent->parent);
+ node = node->parent->parent;
+
+ } else {
+ if (node == node->parent->right) {
+ node = node->parent;
+ ngx_rbtree_left_rotate(root, sentinel, node);
+ }
+
+ ngx_rbt_black(node->parent);
+ ngx_rbt_red(node->parent->parent);
+ ngx_rbtree_right_rotate(root, sentinel, node->parent->parent);
+ }
+
+ } else {
+ temp = node->parent->parent->left;
+
+ if (ngx_rbt_is_red(temp)) {
+ ngx_rbt_black(node->parent);
+ ngx_rbt_black(temp);
+ ngx_rbt_red(node->parent->parent);
+ node = node->parent->parent;
+
+ } else {
+ if (node == node->parent->left) {
+ node = node->parent;
+ ngx_rbtree_right_rotate(root, sentinel, node);
+ }
+
+ ngx_rbt_black(node->parent);
+ ngx_rbt_red(node->parent->parent);
+ ngx_rbtree_left_rotate(root, sentinel, node->parent->parent);
+ }
+ }
+ }
+
+ ngx_rbt_black(*root);
+}
+
+
+void
+ngx_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
+ ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+
+ for ( ;; ) {
+
+ p = (node->key < temp->key) ? &temp->left : &temp->right;
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+void
+ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node,
+ ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+
+ for ( ;; ) {
+
+ /*
+ * Timer values
+ * 1) are spread in small range, usually several minutes,
+ * 2) and overflow each 49 days, if milliseconds are stored in 32 bits.
+ * The comparison takes into account that overflow.
+ */
+
+ /* node->key < temp->key */
+
+ p = ((ngx_rbtree_key_int_t) (node->key - temp->key) < 0)
+ ? &temp->left : &temp->right;
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+void
+ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
+{
+ ngx_uint_t red;
+ ngx_rbtree_node_t **root, *sentinel, *subst, *temp, *w;
+
+ /* a binary tree delete */
+
+ root = &tree->root;
+ sentinel = tree->sentinel;
+
+ if (node->left == sentinel) {
+ temp = node->right;
+ subst = node;
+
+ } else if (node->right == sentinel) {
+ temp = node->left;
+ subst = node;
+
+ } else {
+ subst = ngx_rbtree_min(node->right, sentinel);
+
+ if (subst->left != sentinel) {
+ temp = subst->left;
+ } else {
+ temp = subst->right;
+ }
+ }
+
+ if (subst == *root) {
+ *root = temp;
+ ngx_rbt_black(temp);
+
+ /* DEBUG stuff */
+ node->left = NULL;
+ node->right = NULL;
+ node->parent = NULL;
+ node->key = 0;
+
+ return;
+ }
+
+ red = ngx_rbt_is_red(subst);
+
+ if (subst == subst->parent->left) {
+ subst->parent->left = temp;
+
+ } else {
+ subst->parent->right = temp;
+ }
+
+ if (subst == node) {
+
+ temp->parent = subst->parent;
+
+ } else {
+
+ if (subst->parent == node) {
+ temp->parent = subst;
+
+ } else {
+ temp->parent = subst->parent;
+ }
+
+ subst->left = node->left;
+ subst->right = node->right;
+ subst->parent = node->parent;
+ ngx_rbt_copy_color(subst, node);
+
+ if (node == *root) {
+ *root = subst;
+
+ } else {
+ if (node == node->parent->left) {
+ node->parent->left = subst;
+ } else {
+ node->parent->right = subst;
+ }
+ }
+
+ if (subst->left != sentinel) {
+ subst->left->parent = subst;
+ }
+
+ if (subst->right != sentinel) {
+ subst->right->parent = subst;
+ }
+ }
+
+ /* DEBUG stuff */
+ node->left = NULL;
+ node->right = NULL;
+ node->parent = NULL;
+ node->key = 0;
+
+ if (red) {
+ return;
+ }
+
+ /* a delete fixup */
+
+ while (temp != *root && ngx_rbt_is_black(temp)) {
+
+ if (temp == temp->parent->left) {
+ w = temp->parent->right;
+
+ if (ngx_rbt_is_red(w)) {
+ ngx_rbt_black(w);
+ ngx_rbt_red(temp->parent);
+ ngx_rbtree_left_rotate(root, sentinel, temp->parent);
+ w = temp->parent->right;
+ }
+
+ if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
+ ngx_rbt_red(w);
+ temp = temp->parent;
+
+ } else {
+ if (ngx_rbt_is_black(w->right)) {
+ ngx_rbt_black(w->left);
+ ngx_rbt_red(w);
+ ngx_rbtree_right_rotate(root, sentinel, w);
+ w = temp->parent->right;
+ }
+
+ ngx_rbt_copy_color(w, temp->parent);
+ ngx_rbt_black(temp->parent);
+ ngx_rbt_black(w->right);
+ ngx_rbtree_left_rotate(root, sentinel, temp->parent);
+ temp = *root;
+ }
+
+ } else {
+ w = temp->parent->left;
+
+ if (ngx_rbt_is_red(w)) {
+ ngx_rbt_black(w);
+ ngx_rbt_red(temp->parent);
+ ngx_rbtree_right_rotate(root, sentinel, temp->parent);
+ w = temp->parent->left;
+ }
+
+ if (ngx_rbt_is_black(w->left) && ngx_rbt_is_black(w->right)) {
+ ngx_rbt_red(w);
+ temp = temp->parent;
+
+ } else {
+ if (ngx_rbt_is_black(w->left)) {
+ ngx_rbt_black(w->right);
+ ngx_rbt_red(w);
+ ngx_rbtree_left_rotate(root, sentinel, w);
+ w = temp->parent->left;
+ }
+
+ ngx_rbt_copy_color(w, temp->parent);
+ ngx_rbt_black(temp->parent);
+ ngx_rbt_black(w->left);
+ ngx_rbtree_right_rotate(root, sentinel, temp->parent);
+ temp = *root;
+ }
+ }
+ }
+
+ ngx_rbt_black(temp);
+}
+
+
+static ngx_inline void
+ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
+ ngx_rbtree_node_t *node)
+{
+ ngx_rbtree_node_t *temp;
+
+ temp = node->right;
+ node->right = temp->left;
+
+ if (temp->left != sentinel) {
+ temp->left->parent = node;
+ }
+
+ temp->parent = node->parent;
+
+ if (node == *root) {
+ *root = temp;
+
+ } else if (node == node->parent->left) {
+ node->parent->left = temp;
+
+ } else {
+ node->parent->right = temp;
+ }
+
+ temp->left = node;
+ node->parent = temp;
+}
+
+
+static ngx_inline void
+ngx_rbtree_right_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel,
+ ngx_rbtree_node_t *node)
+{
+ ngx_rbtree_node_t *temp;
+
+ temp = node->left;
+ node->left = temp->right;
+
+ if (temp->right != sentinel) {
+ temp->right->parent = node;
+ }
+
+ temp->parent = node->parent;
+
+ if (node == *root) {
+ *root = temp;
+
+ } else if (node == node->parent->right) {
+ node->parent->right = temp;
+
+ } else {
+ node->parent->left = temp;
+ }
+
+ temp->right = node;
+ node->parent = temp;
+}
+
+
+ngx_rbtree_node_t *
+ngx_rbtree_next(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
+{
+ ngx_rbtree_node_t *root, *sentinel, *parent;
+
+ sentinel = tree->sentinel;
+
+ if (node->right != sentinel) {
+ return ngx_rbtree_min(node->right, sentinel);
+ }
+
+ root = tree->root;
+
+ for ( ;; ) {
+ parent = node->parent;
+
+ if (node == root) {
+ return NULL;
+ }
+
+ if (node == parent->left) {
+ return parent;
+ }
+
+ node = parent;
+ }
+}
diff --git a/app/nginx/src/core/ngx_rbtree.h b/app/nginx/src/core/ngx_rbtree.h
new file mode 100644
index 0000000..97f0e3e
--- /dev/null
+++ b/app/nginx/src/core/ngx_rbtree.h
@@ -0,0 +1,84 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_RBTREE_H_INCLUDED_
+#define _NGX_RBTREE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef ngx_uint_t ngx_rbtree_key_t;
+typedef ngx_int_t ngx_rbtree_key_int_t;
+
+
+typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;
+
+struct ngx_rbtree_node_s {
+ ngx_rbtree_key_t key;
+ ngx_rbtree_node_t *left;
+ ngx_rbtree_node_t *right;
+ ngx_rbtree_node_t *parent;
+ u_char color;
+ u_char data;
+};
+
+
+typedef struct ngx_rbtree_s ngx_rbtree_t;
+
+typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+
+struct ngx_rbtree_s {
+ ngx_rbtree_node_t *root;
+ ngx_rbtree_node_t *sentinel;
+ ngx_rbtree_insert_pt insert;
+};
+
+
+#define ngx_rbtree_init(tree, s, i) \
+ ngx_rbtree_sentinel_init(s); \
+ (tree)->root = s; \
+ (tree)->sentinel = s; \
+ (tree)->insert = i
+
+
+void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
+void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node);
+void ngx_rbtree_insert_value(ngx_rbtree_node_t *root, ngx_rbtree_node_t *node,
+ ngx_rbtree_node_t *sentinel);
+void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+ngx_rbtree_node_t *ngx_rbtree_next(ngx_rbtree_t *tree,
+ ngx_rbtree_node_t *node);
+
+
+#define ngx_rbt_red(node) ((node)->color = 1)
+#define ngx_rbt_black(node) ((node)->color = 0)
+#define ngx_rbt_is_red(node) ((node)->color)
+#define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node))
+#define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color)
+
+
+/* a sentinel must be black */
+
+#define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node)
+
+
+static ngx_inline ngx_rbtree_node_t *
+ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ while (node->left != sentinel) {
+ node = node->left;
+ }
+
+ return node;
+}
+
+
+#endif /* _NGX_RBTREE_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_regex.c b/app/nginx/src/core/ngx_regex.c
new file mode 100644
index 0000000..9939dce
--- /dev/null
+++ b/app/nginx/src/core/ngx_regex.c
@@ -0,0 +1,435 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ ngx_flag_t pcre_jit;
+} ngx_regex_conf_t;
+
+
+static void * ngx_libc_cdecl ngx_regex_malloc(size_t size);
+static void ngx_libc_cdecl ngx_regex_free(void *p);
+#if (NGX_HAVE_PCRE_JIT)
+static void ngx_pcre_free_studies(void *data);
+#endif
+
+static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle);
+
+static void *ngx_regex_create_conf(ngx_cycle_t *cycle);
+static char *ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static char *ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data);
+static ngx_conf_post_t ngx_regex_pcre_jit_post = { ngx_regex_pcre_jit };
+
+
+static ngx_command_t ngx_regex_commands[] = {
+
+ { ngx_string("pcre_jit"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ 0,
+ offsetof(ngx_regex_conf_t, pcre_jit),
+ &ngx_regex_pcre_jit_post },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_regex_module_ctx = {
+ ngx_string("regex"),
+ ngx_regex_create_conf,
+ ngx_regex_init_conf
+};
+
+
+ngx_module_t ngx_regex_module = {
+ NGX_MODULE_V1,
+ &ngx_regex_module_ctx, /* module context */
+ ngx_regex_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ ngx_regex_module_init, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_pool_t *ngx_pcre_pool;
+static ngx_list_t *ngx_pcre_studies;
+
+
+void
+ngx_regex_init(void)
+{
+ pcre_malloc = ngx_regex_malloc;
+ pcre_free = ngx_regex_free;
+}
+
+
+static ngx_inline void
+ngx_regex_malloc_init(ngx_pool_t *pool)
+{
+ ngx_pcre_pool = pool;
+}
+
+
+static ngx_inline void
+ngx_regex_malloc_done(void)
+{
+ ngx_pcre_pool = NULL;
+}
+
+
+ngx_int_t
+ngx_regex_compile(ngx_regex_compile_t *rc)
+{
+ int n, erroff;
+ char *p;
+ pcre *re;
+ const char *errstr;
+ ngx_regex_elt_t *elt;
+
+ ngx_regex_malloc_init(rc->pool);
+
+ re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
+ &errstr, &erroff, NULL);
+
+ /* ensure that there is no current pool */
+ ngx_regex_malloc_done();
+
+ if (re == NULL) {
+ if ((size_t) erroff == rc->pattern.len) {
+ rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+ "pcre_compile() failed: %s in \"%V\"",
+ errstr, &rc->pattern)
+ - rc->err.data;
+
+ } else {
+ rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+ "pcre_compile() failed: %s in \"%V\" at \"%s\"",
+ errstr, &rc->pattern, rc->pattern.data + erroff)
+ - rc->err.data;
+ }
+
+ return NGX_ERROR;
+ }
+
+ rc->regex = ngx_pcalloc(rc->pool, sizeof(ngx_regex_t));
+ if (rc->regex == NULL) {
+ goto nomem;
+ }
+
+ rc->regex->code = re;
+
+ /* do not study at runtime */
+
+ if (ngx_pcre_studies != NULL) {
+ elt = ngx_list_push(ngx_pcre_studies);
+ if (elt == NULL) {
+ goto nomem;
+ }
+
+ elt->regex = rc->regex;
+ elt->name = rc->pattern.data;
+ }
+
+ n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
+ if (n < 0) {
+ p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
+ goto failed;
+ }
+
+ if (rc->captures == 0) {
+ return NGX_OK;
+ }
+
+ n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMECOUNT, &rc->named_captures);
+ if (n < 0) {
+ p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMECOUNT) failed: %d";
+ goto failed;
+ }
+
+ if (rc->named_captures == 0) {
+ return NGX_OK;
+ }
+
+ n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMEENTRYSIZE, &rc->name_size);
+ if (n < 0) {
+ p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMEENTRYSIZE) failed: %d";
+ goto failed;
+ }
+
+ n = pcre_fullinfo(re, NULL, PCRE_INFO_NAMETABLE, &rc->names);
+ if (n < 0) {
+ p = "pcre_fullinfo(\"%V\", PCRE_INFO_NAMETABLE) failed: %d";
+ goto failed;
+ }
+
+ return NGX_OK;
+
+failed:
+
+ rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
+ - rc->err.data;
+ return NGX_ERROR;
+
+nomem:
+
+ rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
+ "regex \"%V\" compilation failed: no memory",
+ &rc->pattern)
+ - rc->err.data;
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log)
+{
+ ngx_int_t n;
+ ngx_uint_t i;
+ ngx_regex_elt_t *re;
+
+ re = a->elts;
+
+ for (i = 0; i < a->nelts; i++) {
+
+ n = ngx_regex_exec(re[i].regex, s, NULL, 0);
+
+ if (n == NGX_REGEX_NO_MATCHED) {
+ continue;
+ }
+
+ if (n < 0) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ ngx_regex_exec_n " failed: %i on \"%V\" using \"%s\"",
+ n, s, re[i].name);
+ return NGX_ERROR;
+ }
+
+ /* match */
+
+ return NGX_OK;
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static void * ngx_libc_cdecl
+ngx_regex_malloc(size_t size)
+{
+ ngx_pool_t *pool;
+ pool = ngx_pcre_pool;
+
+ if (pool) {
+ return ngx_palloc(pool, size);
+ }
+
+ return NULL;
+}
+
+
+static void ngx_libc_cdecl
+ngx_regex_free(void *p)
+{
+ return;
+}
+
+
+#if (NGX_HAVE_PCRE_JIT)
+
+static void
+ngx_pcre_free_studies(void *data)
+{
+ ngx_list_t *studies = data;
+
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_regex_elt_t *elts;
+
+ part = &studies->part;
+ elts = part->elts;
+
+ for (i = 0 ; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ elts = part->elts;
+ i = 0;
+ }
+
+ if (elts[i].regex->extra != NULL) {
+ pcre_free_study(elts[i].regex->extra);
+ }
+ }
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_regex_module_init(ngx_cycle_t *cycle)
+{
+ int opt;
+ const char *errstr;
+ ngx_uint_t i;
+ ngx_list_part_t *part;
+ ngx_regex_elt_t *elts;
+
+ opt = 0;
+
+#if (NGX_HAVE_PCRE_JIT)
+ {
+ ngx_regex_conf_t *rcf;
+ ngx_pool_cleanup_t *cln;
+
+ rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module);
+
+ if (rcf->pcre_jit) {
+ opt = PCRE_STUDY_JIT_COMPILE;
+
+ /*
+ * The PCRE JIT compiler uses mmap for its executable codes, so we
+ * have to explicitly call the pcre_free_study() function to free
+ * this memory.
+ */
+
+ cln = ngx_pool_cleanup_add(cycle->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_pcre_free_studies;
+ cln->data = ngx_pcre_studies;
+ }
+ }
+#endif
+
+ ngx_regex_malloc_init(cycle->pool);
+
+ part = &ngx_pcre_studies->part;
+ elts = part->elts;
+
+ for (i = 0 ; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ elts = part->elts;
+ i = 0;
+ }
+
+ elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr);
+
+ if (errstr != NULL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "pcre_study() failed: %s in \"%s\"",
+ errstr, elts[i].name);
+ }
+
+#if (NGX_HAVE_PCRE_JIT)
+ if (opt & PCRE_STUDY_JIT_COMPILE) {
+ int jit, n;
+
+ jit = 0;
+ n = pcre_fullinfo(elts[i].regex->code, elts[i].regex->extra,
+ PCRE_INFO_JIT, &jit);
+
+ if (n != 0 || jit != 1) {
+ ngx_log_error(NGX_LOG_INFO, cycle->log, 0,
+ "JIT compiler does not support pattern: \"%s\"",
+ elts[i].name);
+ }
+ }
+#endif
+ }
+
+ ngx_regex_malloc_done();
+
+ ngx_pcre_studies = NULL;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_regex_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_regex_conf_t *rcf;
+
+ rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t));
+ if (rcf == NULL) {
+ return NULL;
+ }
+
+ rcf->pcre_jit = NGX_CONF_UNSET;
+
+ ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t));
+ if (ngx_pcre_studies == NULL) {
+ return NULL;
+ }
+
+ return rcf;
+}
+
+
+static char *
+ngx_regex_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_regex_conf_t *rcf = conf;
+
+ ngx_conf_init_value(rcf->pcre_jit, 0);
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data)
+{
+ ngx_flag_t *fp = data;
+
+ if (*fp == 0) {
+ return NGX_CONF_OK;
+ }
+
+#if (NGX_HAVE_PCRE_JIT)
+ {
+ int jit, r;
+
+ jit = 0;
+ r = pcre_config(PCRE_CONFIG_JIT, &jit);
+
+ if (r != 0 || jit != 1) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "PCRE library does not support JIT");
+ *fp = 0;
+ }
+ }
+#else
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "nginx was built without PCRE JIT support");
+ *fp = 0;
+#endif
+
+ return NGX_CONF_OK;
+}
diff --git a/app/nginx/src/core/ngx_regex.h b/app/nginx/src/core/ngx_regex.h
new file mode 100644
index 0000000..680486c
--- /dev/null
+++ b/app/nginx/src/core/ngx_regex.h
@@ -0,0 +1,60 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_REGEX_H_INCLUDED_
+#define _NGX_REGEX_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+#include <pcre.h>
+
+
+#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */
+
+#define NGX_REGEX_CASELESS PCRE_CASELESS
+
+
+typedef struct {
+ pcre *code;
+ pcre_extra *extra;
+} ngx_regex_t;
+
+
+typedef struct {
+ ngx_str_t pattern;
+ ngx_pool_t *pool;
+ ngx_int_t options;
+
+ ngx_regex_t *regex;
+ int captures;
+ int named_captures;
+ int name_size;
+ u_char *names;
+ ngx_str_t err;
+} ngx_regex_compile_t;
+
+
+typedef struct {
+ ngx_regex_t *regex;
+ u_char *name;
+} ngx_regex_elt_t;
+
+
+void ngx_regex_init(void);
+ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc);
+
+#define ngx_regex_exec(re, s, captures, size) \
+ pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \
+ captures, size)
+#define ngx_regex_exec_n "pcre_exec()"
+
+ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log);
+
+
+#endif /* _NGX_REGEX_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_resolver.c b/app/nginx/src/core/ngx_resolver.c
new file mode 100644
index 0000000..e140ab6
--- /dev/null
+++ b/app/nginx/src/core/ngx_resolver.c
@@ -0,0 +1,4662 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_RESOLVER_UDP_SIZE 4096
+
+#define NGX_RESOLVER_TCP_RSIZE (2 + 65535)
+#define NGX_RESOLVER_TCP_WSIZE 8192
+
+
+typedef struct {
+ u_char ident_hi;
+ u_char ident_lo;
+ u_char flags_hi;
+ u_char flags_lo;
+ u_char nqs_hi;
+ u_char nqs_lo;
+ u_char nan_hi;
+ u_char nan_lo;
+ u_char nns_hi;
+ u_char nns_lo;
+ u_char nar_hi;
+ u_char nar_lo;
+} ngx_resolver_hdr_t;
+
+
+typedef struct {
+ u_char type_hi;
+ u_char type_lo;
+ u_char class_hi;
+ u_char class_lo;
+} ngx_resolver_qs_t;
+
+
+typedef struct {
+ u_char type_hi;
+ u_char type_lo;
+ u_char class_hi;
+ u_char class_lo;
+ u_char ttl[4];
+ u_char len_hi;
+ u_char len_lo;
+} ngx_resolver_an_t;
+
+
+#define ngx_resolver_node(n) \
+ (ngx_resolver_node_t *) \
+ ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
+
+
+static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
+static ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec);
+
+
+static void ngx_resolver_cleanup(void *data);
+static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
+static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
+ ngx_resolver_ctx_t *ctx, ngx_str_t *name);
+static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
+ ngx_queue_t *queue);
+static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn);
+static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r,
+ ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
+static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r,
+ ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
+static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_str_t *name);
+static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_str_t *name);
+static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr);
+static void ngx_resolver_resend_handler(ngx_event_t *ev);
+static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
+ ngx_queue_t *queue);
+static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
+static void ngx_resolver_udp_read(ngx_event_t *rev);
+static void ngx_resolver_tcp_write(ngx_event_t *wev);
+static void ngx_resolver_tcp_read(ngx_event_t *rev);
+static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
+ size_t n, ngx_uint_t tcp);
+static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
+static void ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
+ ngx_uint_t trunc, ngx_uint_t ans);
+static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
+static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
+ ngx_str_t *name, uint32_t hash);
+static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r,
+ ngx_str_t *name, uint32_t hash);
+static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
+ in_addr_t addr);
+static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
+ u_char *buf, u_char *src, u_char *last);
+static void ngx_resolver_timeout_handler(ngx_event_t *ev);
+static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
+static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
+static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
+static void ngx_resolver_free(ngx_resolver_t *r, void *p);
+static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
+static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
+static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_uint_t rotate);
+static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx);
+static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
+static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx,
+ ngx_resolver_node_t *rn);
+static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx);
+static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two);
+
+#if (NGX_HAVE_INET6)
+static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
+ struct in6_addr *addr, uint32_t hash);
+#endif
+
+
+ngx_resolver_t *
+ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
+{
+ ngx_str_t s;
+ ngx_url_t u;
+ ngx_uint_t i, j;
+ ngx_resolver_t *r;
+ ngx_pool_cleanup_t *cln;
+ ngx_resolver_connection_t *rec;
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_resolver_cleanup;
+
+ r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ cln->data = r;
+
+ r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
+ if (r->event == NULL) {
+ return NULL;
+ }
+
+ ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
+ ngx_resolver_rbtree_insert_value);
+
+ ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel,
+ ngx_resolver_rbtree_insert_value);
+
+ ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
+ ngx_rbtree_insert_value);
+
+ ngx_queue_init(&r->name_resend_queue);
+ ngx_queue_init(&r->srv_resend_queue);
+ ngx_queue_init(&r->addr_resend_queue);
+
+ ngx_queue_init(&r->name_expire_queue);
+ ngx_queue_init(&r->srv_expire_queue);
+ ngx_queue_init(&r->addr_expire_queue);
+
+#if (NGX_HAVE_INET6)
+ r->ipv6 = 1;
+
+ ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
+ ngx_resolver_rbtree_insert_addr6_value);
+
+ ngx_queue_init(&r->addr6_resend_queue);
+
+ ngx_queue_init(&r->addr6_expire_queue);
+#endif
+
+ r->event->handler = ngx_resolver_resend_handler;
+ r->event->data = r;
+ r->event->log = &cf->cycle->new_log;
+ r->ident = -1;
+
+ r->resend_timeout = 5;
+ r->tcp_timeout = 5;
+ r->expire = 30;
+ r->valid = 0;
+
+ r->log = &cf->cycle->new_log;
+ r->log_level = NGX_LOG_ERR;
+
+ if (n) {
+ if (ngx_array_init(&r->connections, cf->pool, n,
+ sizeof(ngx_resolver_connection_t))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+ }
+
+ for (i = 0; i < n; i++) {
+ if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
+ s.len = names[i].len - 6;
+ s.data = names[i].data + 6;
+
+ r->valid = ngx_parse_time(&s, 1);
+
+ if (r->valid == (time_t) NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter: %V", &names[i]);
+ return NULL;
+ }
+
+ continue;
+ }
+
+#if (NGX_HAVE_INET6)
+ if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
+
+ if (ngx_strcmp(&names[i].data[5], "on") == 0) {
+ r->ipv6 = 1;
+
+ } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
+ r->ipv6 = 0;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter: %V", &names[i]);
+ return NULL;
+ }
+
+ continue;
+ }
+#endif
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url = names[i];
+ u.default_port = 53;
+
+ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%s in resolver \"%V\"",
+ u.err, &u.url);
+ }
+
+ return NULL;
+ }
+
+ rec = ngx_array_push_n(&r->connections, u.naddrs);
+ if (rec == NULL) {
+ return NULL;
+ }
+
+ ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
+
+ for (j = 0; j < u.naddrs; j++) {
+ rec[j].sockaddr = u.addrs[j].sockaddr;
+ rec[j].socklen = u.addrs[j].socklen;
+ rec[j].server = u.addrs[j].name;
+ rec[j].resolver = r;
+ }
+ }
+
+ return r;
+}
+
+
+static void
+ngx_resolver_cleanup(void *data)
+{
+ ngx_resolver_t *r = data;
+
+ ngx_uint_t i;
+ ngx_resolver_connection_t *rec;
+
+ if (r) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "cleanup resolver");
+
+ ngx_resolver_cleanup_tree(r, &r->name_rbtree);
+
+ ngx_resolver_cleanup_tree(r, &r->srv_rbtree);
+
+ ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
+
+#if (NGX_HAVE_INET6)
+ ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
+#endif
+
+ if (r->event) {
+ if (r->event->timer_set) {
+ ngx_del_timer(r->event);
+ }
+
+ ngx_free(r->event);
+ }
+
+
+ rec = r->connections.elts;
+
+ for (i = 0; i < r->connections.nelts; i++) {
+ if (rec[i].udp) {
+ ngx_close_connection(rec[i].udp);
+ }
+
+ if (rec[i].tcp) {
+ ngx_close_connection(rec[i].tcp);
+ }
+
+ if (rec[i].read_buf) {
+ ngx_resolver_free(r, rec[i].read_buf->start);
+ ngx_resolver_free(r, rec[i].read_buf);
+ }
+
+ if (rec[i].write_buf) {
+ ngx_resolver_free(r, rec[i].write_buf->start);
+ ngx_resolver_free(r, rec[i].write_buf);
+ }
+ }
+
+ ngx_free(r);
+ }
+}
+
+
+static void
+ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
+{
+ ngx_resolver_ctx_t *ctx, *next;
+ ngx_resolver_node_t *rn;
+
+ while (tree->root != tree->sentinel) {
+
+ rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
+
+ ngx_queue_remove(&rn->queue);
+
+ for (ctx = rn->waiting; ctx; ctx = next) {
+ next = ctx->next;
+
+ if (ctx->event) {
+ if (ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
+ ngx_resolver_free(r, ctx->event);
+ }
+
+ ngx_resolver_free(r, ctx);
+ }
+
+ ngx_rbtree_delete(tree, &rn->node);
+
+ ngx_resolver_free_node(r, rn);
+ }
+}
+
+
+ngx_resolver_ctx_t *
+ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
+{
+ in_addr_t addr;
+ ngx_resolver_ctx_t *ctx;
+
+ if (temp) {
+ addr = ngx_inet_addr(temp->name.data, temp->name.len);
+
+ if (addr != INADDR_NONE) {
+ temp->resolver = r;
+ temp->state = NGX_OK;
+ temp->naddrs = 1;
+ temp->addrs = &temp->addr;
+ temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
+ temp->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
+ temp->sin.sin_family = AF_INET;
+ temp->sin.sin_addr.s_addr = addr;
+ temp->quick = 1;
+
+ return temp;
+ }
+ }
+
+ if (r->connections.nelts == 0) {
+ return NGX_NO_RESOLVER;
+ }
+
+ ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
+
+ if (ctx) {
+ ctx->resolver = r;
+ }
+
+ return ctx;
+}
+
+
+ngx_int_t
+ngx_resolve_name(ngx_resolver_ctx_t *ctx)
+{
+ size_t slen;
+ ngx_int_t rc;
+ ngx_str_t name;
+ ngx_resolver_t *r;
+
+ r = ctx->resolver;
+
+ if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
+ ctx->name.len--;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve: \"%V\"", &ctx->name);
+
+ if (ctx->quick) {
+ ctx->handler(ctx);
+ return NGX_OK;
+ }
+
+ if (ctx->service.len) {
+ slen = ctx->service.len;
+
+ if (ngx_strlchr(ctx->service.data,
+ ctx->service.data + ctx->service.len, '.')
+ == NULL)
+ {
+ slen += sizeof("_._tcp") - 1;
+ }
+
+ name.len = slen + 1 + ctx->name.len;
+
+ name.data = ngx_resolver_alloc(r, name.len);
+ if (name.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (slen == ctx->service.len) {
+ ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name);
+
+ } else {
+ ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name);
+ }
+
+ /* lock name mutex */
+
+ rc = ngx_resolve_name_locked(r, ctx, &name);
+
+ ngx_resolver_free(r, name.data);
+
+ } else {
+ /* lock name mutex */
+
+ rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
+ }
+
+ if (rc == NGX_OK) {
+ return NGX_OK;
+ }
+
+ /* unlock name mutex */
+
+ if (rc == NGX_AGAIN) {
+ return NGX_OK;
+ }
+
+ /* NGX_ERROR */
+
+ if (ctx->event) {
+ ngx_resolver_free(r, ctx->event);
+ }
+
+ ngx_resolver_free(r, ctx);
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
+{
+ ngx_uint_t i;
+ ngx_resolver_t *r;
+ ngx_resolver_ctx_t *w, **p;
+ ngx_resolver_node_t *rn;
+
+ r = ctx->resolver;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve name done: %i", ctx->state);
+
+ if (ctx->quick) {
+ return;
+ }
+
+ if (ctx->event && ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
+ /* lock name mutex */
+
+ if (ctx->nsrvs) {
+ for (i = 0; i < ctx->nsrvs; i++) {
+ if (ctx->srvs[i].ctx) {
+ ngx_resolve_name_done(ctx->srvs[i].ctx);
+ }
+
+ if (ctx->srvs[i].addrs) {
+ ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr);
+ ngx_resolver_free(r, ctx->srvs[i].addrs);
+ }
+
+ ngx_resolver_free(r, ctx->srvs[i].name.data);
+ }
+
+ ngx_resolver_free(r, ctx->srvs);
+ }
+
+ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
+
+ rn = ctx->node;
+
+ if (rn) {
+ p = &rn->waiting;
+ w = rn->waiting;
+
+ while (w) {
+ if (w == ctx) {
+ *p = w->next;
+
+ goto done;
+ }
+
+ p = &w->next;
+ w = w->next;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+ "could not cancel %V resolving", &ctx->name);
+ }
+ }
+
+done:
+
+ if (ctx->service.len) {
+ ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue);
+
+ } else {
+ ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
+ }
+
+ /* unlock name mutex */
+
+ /* lock alloc mutex */
+
+ if (ctx->event) {
+ ngx_resolver_free_locked(r, ctx->event);
+ }
+
+ ngx_resolver_free_locked(r, ctx);
+
+ /* unlock alloc mutex */
+
+ if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
+ ngx_del_timer(r->event);
+ }
+}
+
+
+static ngx_int_t
+ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
+ ngx_str_t *name)
+{
+ uint32_t hash;
+ ngx_int_t rc;
+ ngx_str_t cname;
+ ngx_uint_t i, naddrs;
+ ngx_queue_t *resend_queue, *expire_queue;
+ ngx_rbtree_t *tree;
+ ngx_resolver_ctx_t *next, *last;
+ ngx_resolver_addr_t *addrs;
+ ngx_resolver_node_t *rn;
+
+ ngx_strlow(name->data, name->data, name->len);
+
+ hash = ngx_crc32_short(name->data, name->len);
+
+ if (ctx->service.len) {
+ rn = ngx_resolver_lookup_srv(r, name, hash);
+
+ tree = &r->srv_rbtree;
+ resend_queue = &r->srv_resend_queue;
+ expire_queue = &r->srv_expire_queue;
+
+ } else {
+ rn = ngx_resolver_lookup_name(r, name, hash);
+
+ tree = &r->name_rbtree;
+ resend_queue = &r->name_resend_queue;
+ expire_queue = &r->name_expire_queue;
+ }
+
+ if (rn) {
+
+ /* ctx can be a list after NGX_RESOLVE_CNAME */
+ for (last = ctx; last->next; last = last->next);
+
+ if (rn->valid >= ngx_time()) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(expire_queue, &rn->queue);
+
+ naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
+#endif
+
+ if (naddrs) {
+
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
+
+ } else {
+ addrs = ngx_resolver_export(r, rn, 1);
+ if (addrs == NULL) {
+ return NGX_ERROR;
+ }
+ }
+
+ last->next = rn->waiting;
+ rn->waiting = NULL;
+
+ /* unlock name mutex */
+
+ do {
+ ctx->state = NGX_OK;
+ ctx->valid = rn->valid;
+ ctx->naddrs = naddrs;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
+
+ next = ctx->next;
+
+ ctx->handler(ctx);
+
+ ctx = next;
+ } while (ctx);
+
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
+ ngx_resolver_free(r, addrs);
+ }
+
+ return NGX_OK;
+ }
+
+ if (rn->nsrvs) {
+ last->next = rn->waiting;
+ rn->waiting = NULL;
+
+ /* unlock name mutex */
+
+ do {
+ next = ctx->next;
+
+ ngx_resolver_resolve_srv_names(ctx, rn);
+
+ ctx = next;
+ } while (ctx);
+
+ return NGX_OK;
+ }
+
+ /* NGX_RESOLVE_CNAME */
+
+ if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
+
+ cname.len = rn->cnlen;
+ cname.data = rn->u.cname;
+
+ return ngx_resolve_name_locked(r, ctx, &cname);
+ }
+
+ last->next = rn->waiting;
+ rn->waiting = NULL;
+
+ /* unlock name mutex */
+
+ do {
+ ctx->state = NGX_RESOLVE_NXDOMAIN;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+ next = ctx->next;
+
+ ctx->handler(ctx);
+
+ ctx = next;
+ } while (ctx);
+
+ return NGX_OK;
+ }
+
+ if (rn->waiting) {
+
+ if (ctx->event == NULL && ctx->timeout) {
+ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+ if (ctx->event == NULL) {
+ return NGX_ERROR;
+ }
+
+ ctx->event->handler = ngx_resolver_timeout_handler;
+ ctx->event->data = ctx;
+ ctx->event->log = r->log;
+ ctx->ident = -1;
+
+ ngx_add_timer(ctx->event, ctx->timeout);
+ }
+
+ last->next = rn->waiting;
+ rn->waiting = ctx;
+ ctx->state = NGX_AGAIN;
+
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
+ return NGX_AGAIN;
+ }
+
+ ngx_queue_remove(&rn->queue);
+
+ /* lock alloc mutex */
+
+ if (rn->query) {
+ ngx_resolver_free_locked(r, rn->query);
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+ }
+
+ if (rn->cnlen) {
+ ngx_resolver_free_locked(r, rn->u.cname);
+ }
+
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u.addrs);
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
+ if (rn->nsrvs) {
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
+ if (rn->u.srvs[i].name.data) {
+ ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
+ }
+ }
+
+ ngx_resolver_free_locked(r, rn->u.srvs);
+ }
+
+ /* unlock alloc mutex */
+
+ } else {
+
+ rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
+ if (rn == NULL) {
+ return NGX_ERROR;
+ }
+
+ rn->name = ngx_resolver_dup(r, name->data, name->len);
+ if (rn->name == NULL) {
+ ngx_resolver_free(r, rn);
+ return NGX_ERROR;
+ }
+
+ rn->node.key = hash;
+ rn->nlen = (u_short) name->len;
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ ngx_rbtree_insert(tree, &rn->node);
+ }
+
+ if (ctx->service.len) {
+ rc = ngx_resolver_create_srv_query(r, rn, name);
+
+ } else {
+ rc = ngx_resolver_create_name_query(r, rn, name);
+ }
+
+ if (rc == NGX_ERROR) {
+ goto failed;
+ }
+
+ if (rc == NGX_DECLINED) {
+ ngx_rbtree_delete(tree, &rn->node);
+
+ ngx_resolver_free(r, rn->query);
+ ngx_resolver_free(r, rn->name);
+ ngx_resolver_free(r, rn);
+
+ do {
+ ctx->state = NGX_RESOLVE_NXDOMAIN;
+ next = ctx->next;
+
+ ctx->handler(ctx);
+
+ ctx = next;
+ } while (ctx);
+
+ return NGX_OK;
+ }
+
+ rn->last_connection = r->last_connection++;
+ if (r->last_connection == r->connections.nelts) {
+ r->last_connection = 0;
+ }
+
+ rn->naddrs = (u_short) -1;
+ rn->tcp = 0;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
+ rn->tcp6 = 0;
+#endif
+ rn->nsrvs = 0;
+
+ if (ngx_resolver_send_query(r, rn) != NGX_OK) {
+ goto failed;
+ }
+
+ if (ctx->event == NULL && ctx->timeout) {
+ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+ if (ctx->event == NULL) {
+ goto failed;
+ }
+
+ ctx->event->handler = ngx_resolver_timeout_handler;
+ ctx->event->data = ctx;
+ ctx->event->log = r->log;
+ ctx->ident = -1;
+
+ ngx_add_timer(ctx->event, ctx->timeout);
+ }
+
+ if (ngx_resolver_resend_empty(r)) {
+ ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
+ }
+
+ rn->expire = ngx_time() + r->resend_timeout;
+
+ ngx_queue_insert_head(resend_queue, &rn->queue);
+
+ rn->code = 0;
+ rn->cnlen = 0;
+ rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
+ rn->waiting = ctx;
+
+ ctx->state = NGX_AGAIN;
+
+ do {
+ ctx->node = rn;
+ ctx = ctx->next;
+ } while (ctx);
+
+ return NGX_AGAIN;
+
+failed:
+
+ ngx_rbtree_delete(tree, &rn->node);
+
+ if (rn->query) {
+ ngx_resolver_free(r, rn->query);
+ }
+
+ ngx_resolver_free(r, rn->name);
+
+ ngx_resolver_free(r, rn);
+
+ return NGX_ERROR;
+}
+
+
+ngx_int_t
+ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
+{
+ u_char *name;
+ in_addr_t addr;
+ ngx_queue_t *resend_queue, *expire_queue;
+ ngx_rbtree_t *tree;
+ ngx_resolver_t *r;
+ struct sockaddr_in *sin;
+ ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ struct sockaddr_in6 *sin6;
+#endif
+
+#if (NGX_SUPPRESS_WARN)
+ addr = 0;
+#if (NGX_HAVE_INET6)
+ hash = 0;
+ sin6 = NULL;
+#endif
+#endif
+
+ r = ctx->resolver;
+
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+ hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+
+ tree = &r->addr6_rbtree;
+ resend_queue = &r->addr6_resend_queue;
+ expire_queue = &r->addr6_expire_queue;
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ resend_queue = &r->addr_resend_queue;
+ expire_queue = &r->addr_expire_queue;
+ }
+
+ if (rn) {
+
+ if (rn->valid >= ngx_time()) {
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(expire_queue, &rn->queue);
+
+ name = ngx_resolver_dup(r, rn->name, rn->nlen);
+ if (name == NULL) {
+ goto failed;
+ }
+
+ ctx->name.len = rn->nlen;
+ ctx->name.data = name;
+
+ /* unlock addr mutex */
+
+ ctx->state = NGX_OK;
+ ctx->valid = rn->valid;
+
+ ctx->handler(ctx);
+
+ ngx_resolver_free(r, name);
+
+ return NGX_OK;
+ }
+
+ if (rn->waiting) {
+
+ if (ctx->event == NULL && ctx->timeout) {
+ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+ if (ctx->event == NULL) {
+ return NGX_ERROR;
+ }
+
+ ctx->event->handler = ngx_resolver_timeout_handler;
+ ctx->event->data = ctx;
+ ctx->event->log = r->log;
+ ctx->ident = -1;
+
+ ngx_add_timer(ctx->event, ctx->timeout);
+ }
+
+ ctx->next = rn->waiting;
+ rn->waiting = ctx;
+ ctx->state = NGX_AGAIN;
+ ctx->node = rn;
+
+ /* unlock addr mutex */
+
+ return NGX_OK;
+ }
+
+ ngx_queue_remove(&rn->queue);
+
+ ngx_resolver_free(r, rn->query);
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ } else {
+ rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
+ if (rn == NULL) {
+ goto failed;
+ }
+
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ rn->addr6 = sin6->sin6_addr;
+ rn->node.key = hash;
+ break;
+#endif
+
+ default: /* AF_INET */
+ rn->node.key = addr;
+ }
+
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ ngx_rbtree_insert(tree, &rn->node);
+ }
+
+ if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
+ goto failed;
+ }
+
+ rn->last_connection = r->last_connection++;
+ if (r->last_connection == r->connections.nelts) {
+ r->last_connection = 0;
+ }
+
+ rn->naddrs = (u_short) -1;
+ rn->tcp = 0;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = (u_short) -1;
+ rn->tcp6 = 0;
+#endif
+ rn->nsrvs = 0;
+
+ if (ngx_resolver_send_query(r, rn) != NGX_OK) {
+ goto failed;
+ }
+
+ if (ctx->event == NULL && ctx->timeout) {
+ ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
+ if (ctx->event == NULL) {
+ goto failed;
+ }
+
+ ctx->event->handler = ngx_resolver_timeout_handler;
+ ctx->event->data = ctx;
+ ctx->event->log = r->log;
+ ctx->ident = -1;
+
+ ngx_add_timer(ctx->event, ctx->timeout);
+ }
+
+ if (ngx_resolver_resend_empty(r)) {
+ ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
+ }
+
+ rn->expire = ngx_time() + r->resend_timeout;
+
+ ngx_queue_insert_head(resend_queue, &rn->queue);
+
+ rn->code = 0;
+ rn->cnlen = 0;
+ rn->name = NULL;
+ rn->nlen = 0;
+ rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
+ rn->waiting = ctx;
+
+ /* unlock addr mutex */
+
+ ctx->state = NGX_AGAIN;
+ ctx->node = rn;
+
+ return NGX_OK;
+
+failed:
+
+ if (rn) {
+ ngx_rbtree_delete(tree, &rn->node);
+
+ if (rn->query) {
+ ngx_resolver_free(r, rn->query);
+ }
+
+ ngx_resolver_free(r, rn);
+ }
+
+ /* unlock addr mutex */
+
+ if (ctx->event) {
+ ngx_resolver_free(r, ctx->event);
+ }
+
+ ngx_resolver_free(r, ctx);
+
+ return NGX_ERROR;
+}
+
+
+void
+ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
+{
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
+ ngx_resolver_t *r;
+ ngx_resolver_ctx_t *w, **p;
+ ngx_resolver_node_t *rn;
+
+ r = ctx->resolver;
+
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+ break;
+#endif
+
+ default: /* AF_INET */
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve addr done: %i", ctx->state);
+
+ if (ctx->event && ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
+ /* lock addr mutex */
+
+ if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
+
+ rn = ctx->node;
+
+ if (rn) {
+ p = &rn->waiting;
+ w = rn->waiting;
+
+ while (w) {
+ if (w == ctx) {
+ *p = w->next;
+
+ goto done;
+ }
+
+ p = &w->next;
+ w = w->next;
+ }
+ }
+
+ {
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addrtext;
+
+ addrtext.data = text;
+ addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
+
+ ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+ "could not cancel %V resolving", &addrtext);
+ }
+ }
+
+done:
+
+ ngx_resolver_expire(r, tree, expire_queue);
+
+ /* unlock addr mutex */
+
+ /* lock alloc mutex */
+
+ if (ctx->event) {
+ ngx_resolver_free_locked(r, ctx->event);
+ }
+
+ ngx_resolver_free_locked(r, ctx);
+
+ /* unlock alloc mutex */
+
+ if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
+ ngx_del_timer(r->event);
+ }
+}
+
+
+static void
+ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
+{
+ time_t now;
+ ngx_uint_t i;
+ ngx_queue_t *q;
+ ngx_resolver_node_t *rn;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
+
+ now = ngx_time();
+
+ for (i = 0; i < 2; i++) {
+ if (ngx_queue_empty(queue)) {
+ return;
+ }
+
+ q = ngx_queue_last(queue);
+
+ rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
+
+ if (now <= rn->expire) {
+ return;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(tree, &rn->node);
+
+ ngx_resolver_free_node(r, rn);
+ }
+}
+
+
+static ngx_int_t
+ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
+{
+ ngx_int_t rc;
+ ngx_resolver_connection_t *rec;
+
+ rec = r->connections.elts;
+ rec = &rec[rn->last_connection];
+
+ if (rec->log.handler == NULL) {
+ rec->log = *r->log;
+ rec->log.handler = ngx_resolver_log_error;
+ rec->log.data = rec;
+ rec->log.action = "resolving";
+ }
+
+ if (rn->naddrs == (u_short) -1) {
+ rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
+ : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
+#if (NGX_HAVE_INET6)
+
+ if (rn->query6 && rn->naddrs6 == (u_short) -1) {
+ rc = rn->tcp6
+ ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
+ : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
+ u_char *query, u_short qlen)
+{
+ ssize_t n;
+
+ if (rec->udp == NULL) {
+ if (ngx_udp_connect(rec) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ rec->udp->data = rec;
+ rec->udp->read->handler = ngx_resolver_udp_read;
+ rec->udp->read->resolver = 1;
+ }
+
+ n = ngx_send(rec->udp, query, qlen);
+
+ if (n == -1) {
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != (size_t) qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
+ u_char *query, u_short qlen)
+{
+ ngx_buf_t *b;
+ ngx_int_t rc;
+
+ rc = NGX_OK;
+
+ if (rec->tcp == NULL) {
+ b = rec->read_buf;
+
+ if (b == NULL) {
+ b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
+ if (b->start == NULL) {
+ ngx_resolver_free(r, b);
+ return NGX_ERROR;
+ }
+
+ b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
+
+ rec->read_buf = b;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+
+ b = rec->write_buf;
+
+ if (b == NULL) {
+ b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
+ if (b->start == NULL) {
+ ngx_resolver_free(r, b);
+ return NGX_ERROR;
+ }
+
+ b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
+
+ rec->write_buf = b;
+ }
+
+ b->pos = b->start;
+ b->last = b->start;
+
+ rc = ngx_tcp_connect(rec);
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ rec->tcp->data = rec;
+ rec->tcp->write->handler = ngx_resolver_tcp_write;
+ rec->tcp->read->handler = ngx_resolver_tcp_read;
+ rec->tcp->read->resolver = 1;
+
+ ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
+ }
+
+ b = rec->write_buf;
+
+ if (b->end - b->last < 2 + qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
+ return NGX_ERROR;
+ }
+
+ *b->last++ = (u_char) (qlen >> 8);
+ *b->last++ = (u_char) qlen;
+ b->last = ngx_cpymem(b->last, query, qlen);
+
+ if (rc == NGX_OK) {
+ ngx_resolver_tcp_write(rec->tcp->write);
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_resolver_resend_handler(ngx_event_t *ev)
+{
+ time_t timer, atimer, stimer, ntimer;
+#if (NGX_HAVE_INET6)
+ time_t a6timer;
+#endif
+ ngx_resolver_t *r;
+
+ r = ev->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver resend handler");
+
+ /* lock name mutex */
+
+ ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
+
+ stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue);
+
+ /* unlock name mutex */
+
+ /* lock addr mutex */
+
+ atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
+
+ /* unlock addr mutex */
+
+#if (NGX_HAVE_INET6)
+
+ /* lock addr6 mutex */
+
+ a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
+
+ /* unlock addr6 mutex */
+
+#endif
+
+ timer = ntimer;
+
+ if (timer == 0) {
+ timer = atimer;
+
+ } else if (atimer) {
+ timer = ngx_min(timer, atimer);
+ }
+
+ if (timer == 0) {
+ timer = stimer;
+
+ } else if (stimer) {
+ timer = ngx_min(timer, stimer);
+ }
+
+#if (NGX_HAVE_INET6)
+
+ if (timer == 0) {
+ timer = a6timer;
+
+ } else if (a6timer) {
+ timer = ngx_min(timer, a6timer);
+ }
+
+#endif
+
+ if (timer) {
+ ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
+ }
+}
+
+
+static time_t
+ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
+{
+ time_t now;
+ ngx_queue_t *q;
+ ngx_resolver_node_t *rn;
+
+ now = ngx_time();
+
+ for ( ;; ) {
+ if (ngx_queue_empty(queue)) {
+ return 0;
+ }
+
+ q = ngx_queue_last(queue);
+
+ rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
+
+ if (now < rn->expire) {
+ return rn->expire - now;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver resend \"%*s\" %p",
+ (size_t) rn->nlen, rn->name, rn->waiting);
+
+ ngx_queue_remove(q);
+
+ if (rn->waiting) {
+
+ if (++rn->last_connection == r->connections.nelts) {
+ rn->last_connection = 0;
+ }
+
+ (void) ngx_resolver_send_query(r, rn);
+
+ rn->expire = now + r->resend_timeout;
+
+ ngx_queue_insert_head(queue, q);
+
+ continue;
+ }
+
+ ngx_rbtree_delete(tree, &rn->node);
+
+ ngx_resolver_free_node(r, rn);
+ }
+}
+
+
+static ngx_uint_t
+ngx_resolver_resend_empty(ngx_resolver_t *r)
+{
+ return ngx_queue_empty(&r->name_resend_queue)
+ && ngx_queue_empty(&r->srv_resend_queue)
+#if (NGX_HAVE_INET6)
+ && ngx_queue_empty(&r->addr6_resend_queue)
+#endif
+ && ngx_queue_empty(&r->addr_resend_queue);
+}
+
+
+static void
+ngx_resolver_udp_read(ngx_event_t *rev)
+{
+ ssize_t n;
+ ngx_connection_t *c;
+ ngx_resolver_connection_t *rec;
+ u_char buf[NGX_RESOLVER_UDP_SIZE];
+
+ c = rev->data;
+ rec = c->data;
+
+ do {
+ n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
+
+ if (n < 0) {
+ return;
+ }
+
+ ngx_resolver_process_response(rec->resolver, buf, n, 0);
+
+ } while (rev->ready);
+}
+
+
+static void
+ngx_resolver_tcp_write(ngx_event_t *wev)
+{
+ off_t sent;
+ ssize_t n;
+ ngx_buf_t *b;
+ ngx_resolver_t *r;
+ ngx_connection_t *c;
+ ngx_resolver_connection_t *rec;
+
+ c = wev->data;
+ rec = c->data;
+ b = rec->write_buf;
+ r = rec->resolver;
+
+ if (wev->timedout) {
+ goto failed;
+ }
+
+ sent = c->sent;
+
+ while (wev->ready && b->pos < b->last) {
+ n = ngx_send(c, b->pos, b->last - b->pos);
+
+ if (n == NGX_AGAIN) {
+ break;
+ }
+
+ if (n == NGX_ERROR) {
+ goto failed;
+ }
+
+ b->pos += n;
+ }
+
+ if (b->pos != b->start) {
+ b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
+ b->pos = b->start;
+ }
+
+ if (c->sent != sent) {
+ ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
+ }
+
+ if (ngx_handle_write_event(wev, 0) != NGX_OK) {
+ goto failed;
+ }
+
+ return;
+
+failed:
+
+ ngx_close_connection(c);
+ rec->tcp = NULL;
+}
+
+
+static void
+ngx_resolver_tcp_read(ngx_event_t *rev)
+{
+ u_char *p;
+ size_t size;
+ ssize_t n;
+ u_short qlen;
+ ngx_buf_t *b;
+ ngx_resolver_t *r;
+ ngx_connection_t *c;
+ ngx_resolver_connection_t *rec;
+
+ c = rev->data;
+ rec = c->data;
+ b = rec->read_buf;
+ r = rec->resolver;
+
+ while (rev->ready) {
+ n = ngx_recv(c, b->last, b->end - b->last);
+
+ if (n == NGX_AGAIN) {
+ break;
+ }
+
+ if (n == NGX_ERROR || n == 0) {
+ goto failed;
+ }
+
+ b->last += n;
+
+ for ( ;; ) {
+ p = b->pos;
+ size = b->last - p;
+
+ if (size < 2) {
+ break;
+ }
+
+ qlen = (u_short) *p++ << 8;
+ qlen += *p++;
+
+ if (size < (size_t) (2 + qlen)) {
+ break;
+ }
+
+ ngx_resolver_process_response(r, p, qlen, 1);
+
+ b->pos += 2 + qlen;
+ }
+
+ if (b->pos != b->start) {
+ b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
+ b->pos = b->start;
+ }
+ }
+
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
+ goto failed;
+ }
+
+ return;
+
+failed:
+
+ ngx_close_connection(c);
+ rec->tcp = NULL;
+}
+
+
+static void
+ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t tcp)
+{
+ char *err;
+ ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc,
+ qtype, qclass;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t qident6;
+#endif
+ ngx_queue_t *q;
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *response;
+ ngx_resolver_node_t *rn;
+
+ if (n < sizeof(ngx_resolver_hdr_t)) {
+ goto short_response;
+ }
+
+ response = (ngx_resolver_hdr_t *) buf;
+
+ ident = (response->ident_hi << 8) + response->ident_lo;
+ flags = (response->flags_hi << 8) + response->flags_lo;
+ nqs = (response->nqs_hi << 8) + response->nqs_lo;
+ nan = (response->nan_hi << 8) + response->nan_lo;
+ trunc = flags & 0x0200;
+
+ ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver DNS response %ui fl:%04Xi %ui/%ui/%ud/%ud",
+ ident, flags, nqs, nan,
+ (response->nns_hi << 8) + response->nns_lo,
+ (response->nar_hi << 8) + response->nar_lo);
+
+ /* response to a standard query */
+ if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "invalid %s DNS response %ui fl:%04Xi",
+ tcp ? "TCP" : "UDP", ident, flags);
+ return;
+ }
+
+ code = flags & 0xf;
+
+ if (code == NGX_RESOLVE_FORMERR) {
+
+ times = 0;
+
+ for (q = ngx_queue_head(&r->name_resend_queue);
+ q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
+ q = ngx_queue_next(q))
+ {
+ rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
+ qident = (rn->query[0] << 8) + rn->query[1];
+
+ if (qident == ident) {
+ goto dns_error_name;
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->query6) {
+ qident6 = (rn->query6[0] << 8) + rn->query6[1];
+
+ if (qident6 == ident) {
+ goto dns_error_name;
+ }
+ }
+#endif
+ }
+
+ goto dns_error;
+ }
+
+ if (code > NGX_RESOLVE_REFUSED) {
+ goto dns_error;
+ }
+
+ if (nqs != 1) {
+ err = "invalid number of questions in DNS response";
+ goto done;
+ }
+
+ i = sizeof(ngx_resolver_hdr_t);
+
+ while (i < (ngx_uint_t) n) {
+ if (buf[i] == '\0') {
+ goto found;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ goto short_response;
+
+found:
+
+ if (i++ == sizeof(ngx_resolver_hdr_t)) {
+ err = "zero-length domain name in DNS response";
+ goto done;
+ }
+
+ if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
+ > (ngx_uint_t) n)
+ {
+ goto short_response;
+ }
+
+ qs = (ngx_resolver_qs_t *) &buf[i];
+
+ qtype = (qs->type_hi << 8) + qs->type_lo;
+ qclass = (qs->class_hi << 8) + qs->class_lo;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
+
+ if (qclass != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unknown query class %ui in DNS response", qclass);
+ return;
+ }
+
+ switch (qtype) {
+
+ case NGX_RESOLVE_A:
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+#endif
+
+ ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
+ i + sizeof(ngx_resolver_qs_t));
+
+ break;
+
+ case NGX_RESOLVE_SRV:
+
+ ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc,
+ i + sizeof(ngx_resolver_qs_t));
+
+ break;
+
+ case NGX_RESOLVE_PTR:
+
+ ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
+
+ break;
+
+ default:
+ ngx_log_error(r->log_level, r->log, 0,
+ "unknown query type %ui in DNS response", qtype);
+ return;
+ }
+
+ return;
+
+short_response:
+
+ err = "short DNS response";
+
+done:
+
+ ngx_log_error(r->log_level, r->log, 0, err);
+
+ return;
+
+dns_error_name:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
+ code, ngx_resolver_strerror(code), ident,
+ (size_t) rn->nlen, rn->name);
+ return;
+
+dns_error:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "DNS error (%ui: %s), query id:%ui",
+ code, ngx_resolver_strerror(code), ident);
+ return;
+}
+
+
+static void
+ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
+{
+ char *err;
+ u_char *cname;
+ size_t len;
+ int32_t ttl;
+ uint32_t hash;
+ in_addr_t *addr;
+ ngx_str_t name;
+ ngx_uint_t type, class, qident, naddrs, a, i, j, start;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+#endif
+ ngx_resolver_an_t *an;
+ ngx_resolver_ctx_t *ctx, *next;
+ ngx_resolver_node_t *rn;
+ ngx_resolver_addr_t *addrs;
+ ngx_resolver_connection_t *rec;
+
+ if (ngx_resolver_copy(r, &name, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + n)
+ != NGX_OK)
+ {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
+
+ hash = ngx_crc32_short(name.data, name.len);
+
+ /* lock name mutex */
+
+ rn = ngx_resolver_lookup_name(r, &name, hash);
+
+ if (rn == NULL) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ if (trunc && rn->tcp6) {
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ qident = (rn->query6[0] << 8) + rn->query6[1];
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->query == NULL || rn->naddrs != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ if (trunc && rn->tcp) {
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ qident = (rn->query[0] << 8) + rn->query[1];
+ }
+
+ if (ident != qident) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "wrong ident %ui response for %V, expect %ui",
+ ident, &name, qident);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ ngx_resolver_free(r, name.data);
+
+ if (trunc) {
+
+ ngx_queue_remove(&rn->queue);
+
+ if (rn->waiting == NULL) {
+ ngx_rbtree_delete(&r->name_rbtree, &rn->node);
+ ngx_resolver_free_node(r, rn);
+ goto next;
+ }
+
+ rec = r->connections.elts;
+ rec = &rec[rn->last_connection];
+
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ rn->tcp6 = 1;
+
+ (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ rn->tcp = 1;
+
+ (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
+ }
+
+ rn->expire = ngx_time() + r->resend_timeout;
+
+ ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
+
+ goto next;
+ }
+
+ if (code == 0 && rn->code) {
+ code = rn->code;
+ }
+
+ if (code == 0 && nan == 0) {
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ rn->naddrs6 = 0;
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs) {
+ goto export;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ rn->naddrs = 0;
+
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs6) {
+ goto export;
+ }
+ }
+#endif
+
+ code = NGX_RESOLVE_NXDOMAIN;
+ }
+
+ if (code) {
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ rn->naddrs6 = 0;
+
+ if (rn->naddrs == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ rn->naddrs = 0;
+
+ if (rn->naddrs6 == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+ }
+#endif
+
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ ngx_queue_remove(&rn->queue);
+
+ ngx_rbtree_delete(&r->name_rbtree, &rn->node);
+
+ /* unlock name mutex */
+
+ while (next) {
+ ctx = next;
+ ctx->state = code;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+ next = ctx->next;
+
+ ctx->handler(ctx);
+ }
+
+ ngx_resolver_free_node(r, rn);
+
+ return;
+ }
+
+ i = ans;
+ naddrs = 0;
+ cname = NULL;
+
+ for (a = 0; a < nan; a++) {
+
+ start = i;
+
+ while (i < n) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ goto found;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ goto test_length;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ goto short_response;
+
+ test_length:
+
+ if (i - start < 2) {
+ err = "invalid name in DNS response";
+ goto invalid;
+ }
+
+ found:
+
+ if (i + sizeof(ngx_resolver_an_t) >= n) {
+ goto short_response;
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
+
+ type = (an->type_hi << 8) + an->type_lo;
+ class = (an->class_hi << 8) + an->class_lo;
+ len = (an->len_hi << 8) + an->len_lo;
+ ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ + (an->ttl[2] << 8) + (an->ttl[3]);
+
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
+ if (ttl < 0) {
+ ttl = 0;
+ }
+
+ rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
+
+ i += sizeof(ngx_resolver_an_t);
+
+ switch (type) {
+
+ case NGX_RESOLVE_A:
+
+ if (qtype != NGX_RESOLVE_A) {
+ err = "unexpected A record in DNS response";
+ goto invalid;
+ }
+
+ if (len != 4) {
+ err = "invalid A record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 4 > n) {
+ goto short_response;
+ }
+
+ naddrs++;
+
+ break;
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (qtype != NGX_RESOLVE_AAAA) {
+ err = "unexpected AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (len != 16) {
+ err = "invalid AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 16 > n) {
+ goto short_response;
+ }
+
+ naddrs++;
+
+ break;
+#endif
+
+ case NGX_RESOLVE_CNAME:
+
+ cname = &buf[i];
+
+ break;
+
+ case NGX_RESOLVE_DNAME:
+
+ break;
+
+ default:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR type %ui", type);
+ }
+
+ i += len;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver naddrs:%ui cname:%p ttl:%uD",
+ naddrs, cname, rn->ttl);
+
+ if (naddrs) {
+
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (naddrs == 1) {
+ addr6 = &rn->u6.addr6;
+ rn->naddrs6 = 1;
+
+ } else {
+ addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
+ if (addr6 == NULL) {
+ goto failed;
+ }
+
+ rn->u6.addrs6 = addr6;
+ rn->naddrs6 = (u_short) naddrs;
+ }
+
+#if (NGX_SUPPRESS_WARN)
+ addr = NULL;
+#endif
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ if (naddrs == 1) {
+ addr = &rn->u.addr;
+ rn->naddrs = 1;
+
+ } else {
+ addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
+ if (addr == NULL) {
+ goto failed;
+ }
+
+ rn->u.addrs = addr;
+ rn->naddrs = (u_short) naddrs;
+ }
+
+#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
+ addr6 = NULL;
+#endif
+ }
+
+ j = 0;
+ i = ans;
+
+ for (a = 0; a < nan; a++) {
+
+ for ( ;; ) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ break;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ break;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
+
+ type = (an->type_hi << 8) + an->type_lo;
+ len = (an->len_hi << 8) + an->len_lo;
+
+ i += sizeof(ngx_resolver_an_t);
+
+ if (type == NGX_RESOLVE_A) {
+
+ addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ + (buf[i + 2] << 8) + (buf[i + 3]));
+
+ if (++j == naddrs) {
+
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
+ }
+#endif
+
+ break;
+ }
+ }
+
+#if (NGX_HAVE_INET6)
+ else if (type == NGX_RESOLVE_AAAA) {
+
+ ngx_memcpy(addr6[j].s6_addr, &buf[i], 16);
+
+ if (++j == naddrs) {
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
+
+ break;
+ }
+ }
+#endif
+
+ i += len;
+ }
+ }
+
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->naddrs6 == (u_short) -1) {
+ rn->naddrs6 = 0;
+ }
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->naddrs == (u_short) -1) {
+ rn->naddrs = 0;
+ }
+ }
+
+ if (rn->naddrs != (u_short) -1
+#if (NGX_HAVE_INET6)
+ && rn->naddrs6 != (u_short) -1
+#endif
+ && rn->naddrs
+#if (NGX_HAVE_INET6)
+ + rn->naddrs6
+#endif
+ > 0)
+ {
+
+#if (NGX_HAVE_INET6)
+ export:
+#endif
+
+ naddrs = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += rn->naddrs6;
+#endif
+
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
+
+ } else {
+ addrs = ngx_resolver_export(r, rn, 0);
+ if (addrs == NULL) {
+ goto failed;
+ }
+ }
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
+
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ /* unlock name mutex */
+
+ while (next) {
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->valid = rn->valid;
+ ctx->naddrs = naddrs;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
+
+ next = ctx->next;
+
+ ctx->handler(ctx);
+ }
+
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
+ ngx_resolver_free(r, addrs);
+ }
+
+ ngx_resolver_free(r, rn->query);
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ return;
+ }
+
+ if (cname) {
+
+ /* CNAME only */
+
+ if (rn->naddrs == (u_short) -1
+#if (NGX_HAVE_INET6)
+ || rn->naddrs6 == (u_short) -1
+#endif
+ )
+ {
+ goto next;
+ }
+
+ if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver cname:\"%V\"", &name);
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->cnlen = (u_short) name.len;
+ rn->u.cname = name.data;
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
+
+ ngx_resolver_free(r, rn->query);
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ ctx = rn->waiting;
+ rn->waiting = NULL;
+
+ if (ctx) {
+
+ if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
+
+ /* unlock name mutex */
+
+ do {
+ ctx->state = NGX_RESOLVE_NXDOMAIN;
+ next = ctx->next;
+
+ ctx->handler(ctx);
+
+ ctx = next;
+ } while (ctx);
+
+ return;
+ }
+
+ for (next = ctx; next; next = next->next) {
+ next->node = NULL;
+ }
+
+ (void) ngx_resolve_name_locked(r, ctx, &name);
+ }
+
+ /* unlock name mutex */
+
+ return;
+ }
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "no A or CNAME types in DNS response");
+ return;
+
+short_response:
+
+ err = "short DNS response";
+
+invalid:
+
+ /* unlock name mutex */
+
+ ngx_log_error(r->log_level, r->log, 0, err);
+
+ return;
+
+failed:
+
+next:
+
+ /* unlock name mutex */
+
+ return;
+}
+
+
+static void
+ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
+ ngx_uint_t trunc, ngx_uint_t ans)
+{
+ char *err;
+ u_char *cname;
+ size_t len;
+ int32_t ttl;
+ uint32_t hash;
+ ngx_str_t name;
+ ngx_uint_t type, qident, class, start, nsrvs, a, i, j;
+ ngx_resolver_an_t *an;
+ ngx_resolver_ctx_t *ctx, *next;
+ ngx_resolver_srv_t *srvs;
+ ngx_resolver_node_t *rn;
+ ngx_resolver_connection_t *rec;
+
+ if (ngx_resolver_copy(r, &name, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + n)
+ != NGX_OK)
+ {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
+
+ hash = ngx_crc32_short(name.data, name.len);
+
+ rn = ngx_resolver_lookup_srv(r, &name, hash);
+
+ if (rn == NULL || rn->query == NULL) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ if (trunc && rn->tcp) {
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ qident = (rn->query[0] << 8) + rn->query[1];
+
+ if (ident != qident) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "wrong ident %ui response for %V, expect %ui",
+ ident, &name, qident);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ ngx_resolver_free(r, name.data);
+
+ if (trunc) {
+
+ ngx_queue_remove(&rn->queue);
+
+ if (rn->waiting == NULL) {
+ ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
+ ngx_resolver_free_node(r, rn);
+ return;
+ }
+
+ rec = r->connections.elts;
+ rec = &rec[rn->last_connection];
+
+ rn->tcp = 1;
+
+ (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
+
+ rn->expire = ngx_time() + r->resend_timeout;
+
+ ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue);
+
+ return;
+ }
+
+ if (code == 0 && rn->code) {
+ code = rn->code;
+ }
+
+ if (code == 0 && nan == 0) {
+ code = NGX_RESOLVE_NXDOMAIN;
+ }
+
+ if (code) {
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ ngx_queue_remove(&rn->queue);
+
+ ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
+
+ while (next) {
+ ctx = next;
+ ctx->state = code;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+ next = ctx->next;
+
+ ctx->handler(ctx);
+ }
+
+ ngx_resolver_free_node(r, rn);
+
+ return;
+ }
+
+ i = ans;
+ nsrvs = 0;
+ cname = NULL;
+
+ for (a = 0; a < nan; a++) {
+
+ start = i;
+
+ while (i < n) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ goto found;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ goto test_length;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ goto short_response;
+
+ test_length:
+
+ if (i - start < 2) {
+ err = "invalid name DNS response";
+ goto invalid;
+ }
+
+ found:
+
+ if (i + sizeof(ngx_resolver_an_t) >= n) {
+ goto short_response;
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
+
+ type = (an->type_hi << 8) + an->type_lo;
+ class = (an->class_hi << 8) + an->class_lo;
+ len = (an->len_hi << 8) + an->len_lo;
+ ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ + (an->ttl[2] << 8) + (an->ttl[3]);
+
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
+ if (ttl < 0) {
+ ttl = 0;
+ }
+
+ rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
+
+ i += sizeof(ngx_resolver_an_t);
+
+ switch (type) {
+
+ case NGX_RESOLVE_SRV:
+
+ if (i + 6 > n) {
+ goto short_response;
+ }
+
+ if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ nsrvs++;
+
+ break;
+
+ case NGX_RESOLVE_CNAME:
+
+ cname = &buf[i];
+
+ break;
+
+ case NGX_RESOLVE_DNAME:
+
+ break;
+
+ default:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR type %ui", type);
+ }
+
+ i += len;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver nsrvs:%ui cname:%p ttl:%uD",
+ nsrvs, cname, rn->ttl);
+
+ if (nsrvs) {
+
+ srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t));
+ if (srvs == NULL) {
+ goto failed;
+ }
+
+ rn->u.srvs = srvs;
+ rn->nsrvs = (u_short) nsrvs;
+
+ j = 0;
+ i = ans;
+
+ for (a = 0; a < nan; a++) {
+
+ for ( ;; ) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ break;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ break;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
+
+ type = (an->type_hi << 8) + an->type_lo;
+ len = (an->len_hi << 8) + an->len_lo;
+
+ i += sizeof(ngx_resolver_an_t);
+
+ if (type == NGX_RESOLVE_SRV) {
+
+ srvs[j].priority = (buf[i] << 8) + buf[i + 1];
+ srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3];
+
+ if (srvs[j].weight == 0) {
+ srvs[j].weight = 1;
+ }
+
+ srvs[j].port = (buf[i + 4] << 8) + buf[i + 5];
+
+ if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6],
+ buf + n)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ j++;
+ }
+
+ i += len;
+ }
+
+ ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t),
+ ngx_resolver_cmp_srvs);
+
+ ngx_resolver_free(r, rn->query);
+ rn->query = NULL;
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
+
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ while (next) {
+ ctx = next;
+ next = ctx->next;
+
+ ngx_resolver_resolve_srv_names(ctx, rn);
+ }
+
+ return;
+ }
+
+ rn->nsrvs = 0;
+
+ if (cname) {
+
+ /* CNAME only */
+
+ if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver cname:\"%V\"", &name);
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->cnlen = (u_short) name.len;
+ rn->u.cname = name.data;
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
+
+ ngx_resolver_free(r, rn->query);
+ rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ ctx = rn->waiting;
+ rn->waiting = NULL;
+
+ if (ctx) {
+
+ if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
+
+ /* unlock name mutex */
+
+ do {
+ ctx->state = NGX_RESOLVE_NXDOMAIN;
+ next = ctx->next;
+
+ ctx->handler(ctx);
+
+ ctx = next;
+ } while (ctx);
+
+ return;
+ }
+
+ for (next = ctx; next; next = next->next) {
+ next->node = NULL;
+ }
+
+ (void) ngx_resolve_name_locked(r, ctx, &name);
+ }
+
+ /* unlock name mutex */
+
+ return;
+ }
+
+ ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response");
+
+ return;
+
+short_response:
+
+ err = "short DNS response";
+
+invalid:
+
+ /* unlock name mutex */
+
+ ngx_log_error(r->log_level, r->log, 0, err);
+
+ return;
+
+failed:
+
+ /* unlock name mutex */
+
+ return;
+}
+
+
+static void
+ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn)
+{
+ ngx_uint_t i;
+ ngx_resolver_t *r;
+ ngx_resolver_ctx_t *cctx;
+ ngx_resolver_srv_name_t *srvs;
+
+ r = ctx->resolver;
+
+ ctx->node = NULL;
+ ctx->state = NGX_OK;
+ ctx->valid = rn->valid;
+ ctx->count = rn->nsrvs;
+
+ srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t));
+ if (srvs == NULL) {
+ goto failed;
+ }
+
+ ctx->srvs = srvs;
+ ctx->nsrvs = rn->nsrvs;
+
+ if (ctx->event && ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
+ srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len);
+ if (srvs[i].name.data == NULL) {
+ goto failed;
+ }
+
+ srvs[i].name.len = rn->u.srvs[i].name.len;
+ ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data,
+ srvs[i].name.len);
+
+ cctx = ngx_resolve_start(r, NULL);
+ if (cctx == NULL) {
+ goto failed;
+ }
+
+ cctx->name = srvs[i].name;
+ cctx->handler = ngx_resolver_srv_names_handler;
+ cctx->data = ctx;
+ cctx->srvs = &srvs[i];
+ cctx->timeout = ctx->timeout;
+
+ srvs[i].priority = rn->u.srvs[i].priority;
+ srvs[i].weight = rn->u.srvs[i].weight;
+ srvs[i].port = rn->u.srvs[i].port;
+ srvs[i].ctx = cctx;
+
+ if (ngx_resolve_name(cctx) == NGX_ERROR) {
+ srvs[i].ctx = NULL;
+ goto failed;
+ }
+ }
+
+ return;
+
+failed:
+
+ ctx->state = NGX_ERROR;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+ ctx->handler(ctx);
+}
+
+
+static void
+ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx)
+{
+ ngx_uint_t i;
+ ngx_addr_t *addrs;
+ ngx_resolver_t *r;
+ ngx_sockaddr_t *sockaddr;
+ ngx_resolver_ctx_t *ctx;
+ ngx_resolver_srv_name_t *srv;
+
+ r = cctx->resolver;
+ ctx = cctx->data;
+ srv = cctx->srvs;
+
+ ctx->count--;
+
+ srv->ctx = NULL;
+ srv->state = cctx->state;
+
+ if (cctx->naddrs) {
+
+ ctx->valid = ngx_min(ctx->valid, cctx->valid);
+
+ addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
+ if (addrs == NULL) {
+ ngx_resolve_name_done(cctx);
+
+ ctx->state = NGX_ERROR;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+ ctx->handler(ctx);
+ return;
+ }
+
+ sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t));
+ if (sockaddr == NULL) {
+ ngx_resolver_free(r, addrs);
+ ngx_resolve_name_done(cctx);
+
+ ctx->state = NGX_ERROR;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+ ctx->handler(ctx);
+ return;
+ }
+
+ for (i = 0; i < cctx->naddrs; i++) {
+ addrs[i].sockaddr = &sockaddr[i].sockaddr;
+ addrs[i].socklen = cctx->addrs[i].socklen;
+
+ ngx_memcpy(&sockaddr[i], cctx->addrs[i].sockaddr,
+ addrs[i].socklen);
+
+ ngx_inet_set_port(addrs[i].sockaddr, srv->port);
+ }
+
+ srv->addrs = addrs;
+ srv->naddrs = cctx->naddrs;
+ }
+
+ ngx_resolve_name_done(cctx);
+
+ if (ctx->count == 0) {
+ ngx_resolver_report_srv(r, ctx);
+ }
+}
+
+
+static void
+ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
+{
+ char *err;
+ size_t len;
+ in_addr_t addr;
+ int32_t ttl;
+ ngx_int_t octet;
+ ngx_str_t name;
+ ngx_uint_t mask, type, class, qident, a, i, start;
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
+ ngx_resolver_an_t *an;
+ ngx_resolver_ctx_t *ctx, *next;
+ ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ ngx_int_t digit;
+ struct in6_addr addr6;
+#endif
+
+ if (ngx_resolver_copy(r, &name, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + n)
+ != NGX_OK)
+ {
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
+
+ /* AF_INET */
+
+ addr = 0;
+ i = sizeof(ngx_resolver_hdr_t);
+
+ for (mask = 0; mask < 32; mask += 8) {
+ len = buf[i++];
+
+ octet = ngx_atoi(&buf[i], len);
+ if (octet == NGX_ERROR || octet > 255) {
+ goto invalid_in_addr_arpa;
+ }
+
+ addr += octet << mask;
+ i += len;
+ }
+
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
+ i += sizeof("\7in-addr\4arpa");
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+
+ goto valid;
+ }
+
+invalid_in_addr_arpa:
+
+#if (NGX_HAVE_INET6)
+
+ i = sizeof(ngx_resolver_hdr_t);
+
+ for (octet = 15; octet >= 0; octet--) {
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] = (u_char) digit;
+
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] += (u_char) (digit * 16);
+ }
+
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
+ i += sizeof("\3ip6\4arpa");
+
+ /* lock addr mutex */
+
+ hash = ngx_crc32_short(addr6.s6_addr, 16);
+ rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
+
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+
+ goto valid;
+ }
+
+invalid_ip6_arpa:
+#endif
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "invalid in-addr.arpa or ip6.arpa name in DNS response");
+ ngx_resolver_free(r, name.data);
+ return;
+
+valid:
+
+ if (rn == NULL || rn->query == NULL) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ qident = (rn->query[0] << 8) + rn->query[1];
+
+ if (ident != qident) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "wrong ident %ui response for %V, expect %ui",
+ ident, &name, qident);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ ngx_resolver_free(r, name.data);
+
+ if (code == 0 && nan == 0) {
+ code = NGX_RESOLVE_NXDOMAIN;
+ }
+
+ if (code) {
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ ngx_queue_remove(&rn->queue);
+
+ ngx_rbtree_delete(tree, &rn->node);
+
+ /* unlock addr mutex */
+
+ while (next) {
+ ctx = next;
+ ctx->state = code;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+ next = ctx->next;
+
+ ctx->handler(ctx);
+ }
+
+ ngx_resolver_free_node(r, rn);
+
+ return;
+ }
+
+ i += sizeof(ngx_resolver_qs_t);
+
+ for (a = 0; a < nan; a++) {
+
+ start = i;
+
+ while (i < n) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ goto found;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ goto test_length;
+ }
+
+ i += 1 + buf[i];
+ }
+
+ goto short_response;
+
+ test_length:
+
+ if (i - start < 2) {
+ err = "invalid name in DNS response";
+ goto invalid;
+ }
+
+ found:
+
+ if (i + sizeof(ngx_resolver_an_t) >= n) {
+ goto short_response;
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
+
+ type = (an->type_hi << 8) + an->type_lo;
+ class = (an->class_hi << 8) + an->class_lo;
+ len = (an->len_hi << 8) + an->len_lo;
+ ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ + (an->ttl[2] << 8) + (an->ttl[3]);
+
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
+ if (ttl < 0) {
+ ttl = 0;
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolver qt:%ui cl:%ui len:%uz",
+ type, class, len);
+
+ i += sizeof(ngx_resolver_an_t);
+
+ switch (type) {
+
+ case NGX_RESOLVE_PTR:
+
+ goto ptr;
+
+ case NGX_RESOLVE_CNAME:
+
+ break;
+
+ default:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR type %ui", type);
+ }
+
+ i += len;
+ }
+
+ /* unlock addr mutex */
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "no PTR type in DNS response");
+ return;
+
+ptr:
+
+ if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
+
+ if (name.len != (size_t) rn->nlen
+ || ngx_strncmp(name.data, rn->name, name.len) != 0)
+ {
+ if (rn->nlen) {
+ ngx_resolver_free(r, rn->name);
+ }
+
+ rn->nlen = (u_short) name.len;
+ rn->name = name.data;
+
+ name.data = ngx_resolver_dup(r, rn->name, name.len);
+ if (name.data == NULL) {
+ goto failed;
+ }
+ }
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(expire_queue, &rn->queue);
+
+ next = rn->waiting;
+ rn->waiting = NULL;
+
+ /* unlock addr mutex */
+
+ while (next) {
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->valid = rn->valid;
+ ctx->name = name;
+ next = ctx->next;
+
+ ctx->handler(ctx);
+ }
+
+ ngx_resolver_free(r, name.data);
+
+ return;
+
+short_response:
+
+ err = "short DNS response";
+
+invalid:
+
+ /* unlock addr mutex */
+
+ ngx_log_error(r->log_level, r->log, 0, err);
+
+ return;
+
+failed:
+
+ /* unlock addr mutex */
+
+ return;
+}
+
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_resolver_node_t *rn;
+
+ node = r->name_rbtree.root;
+ sentinel = r->name_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ rn = ngx_resolver_node(node);
+
+ rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
+
+ if (rc == 0) {
+ return rn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_resolver_node_t *rn;
+
+ node = r->srv_rbtree.root;
+ sentinel = r->srv_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ rn = ngx_resolver_node(node);
+
+ rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
+
+ if (rc == 0) {
+ return rn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
+{
+ ngx_rbtree_node_t *node, *sentinel;
+
+ node = r->addr_rbtree.root;
+ sentinel = r->addr_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (addr < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (addr > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* addr == node->key */
+
+ return ngx_resolver_node(node);
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+
+#if (NGX_HAVE_INET6)
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
+ uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_resolver_node_t *rn;
+
+ node = r->addr6_rbtree.root;
+ sentinel = r->addr6_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ rn = ngx_resolver_node(node);
+
+ rc = ngx_memcmp(addr, &rn->addr6, 16);
+
+ if (rc == 0) {
+ return rn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+#endif
+
+
+static void
+ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_resolver_node_t *rn, *rn_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ rn = ngx_resolver_node(node);
+ rn_temp = ngx_resolver_node(temp);
+
+ p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
+ < 0) ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+#if (NGX_HAVE_INET6)
+
+static void
+ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_resolver_node_t *rn, *rn_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ rn = ngx_resolver_node(node);
+ rn_temp = ngx_resolver_node(temp);
+
+ p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
+ < 0) ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+#endif
+
+
+static ngx_int_t
+ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_str_t *name)
+{
+ u_char *p, *s;
+ size_t len, nlen;
+ ngx_uint_t ident;
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *query;
+
+ nlen = name->len ? (1 + name->len + 1) : 1;
+
+ len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
+
+#if (NGX_HAVE_INET6)
+ p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
+#else
+ p = ngx_resolver_alloc(r, len);
+#endif
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ rn->qlen = (u_short) len;
+ rn->query = p;
+
+#if (NGX_HAVE_INET6)
+ if (r->ipv6) {
+ rn->query6 = p + len;
+ }
+#endif
+
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve: \"%V\" A %i", name, ident & 0xffff);
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ /* recursion query */
+ query->flags_hi = 1; query->flags_lo = 0;
+
+ /* one question */
+ query->nqs_hi = 0; query->nqs_lo = 1;
+ query->nan_hi = 0; query->nan_lo = 0;
+ query->nns_hi = 0; query->nns_lo = 0;
+ query->nar_hi = 0; query->nar_lo = 0;
+
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
+
+ qs = (ngx_resolver_qs_t *) p;
+
+ /* query type */
+ qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
+
+ /* IN query class */
+ qs->class_hi = 0; qs->class_lo = 1;
+
+ /* convert "www.example.com" to "\3www\7example\3com\0" */
+
+ len = 0;
+ p--;
+ *p-- = '\0';
+
+ if (name->len == 0) {
+ return NGX_DECLINED;
+ }
+
+ for (s = name->data + name->len - 1; s >= name->data; s--) {
+ if (*s != '.') {
+ *p = *s;
+ len++;
+
+ } else {
+ if (len == 0 || len > 255) {
+ return NGX_DECLINED;
+ }
+
+ *p = (u_char) len;
+ len = 0;
+ }
+
+ p--;
+ }
+
+ if (len == 0 || len > 255) {
+ return NGX_DECLINED;
+ }
+
+ *p = (u_char) len;
+
+#if (NGX_HAVE_INET6)
+ if (!r->ipv6) {
+ return NGX_OK;
+ }
+
+ p = rn->query6;
+
+ ngx_memcpy(p, rn->query, rn->qlen);
+
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
+
+ qs = (ngx_resolver_qs_t *) p;
+
+ qs->type_lo = NGX_RESOLVE_AAAA;
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_str_t *name)
+{
+ u_char *p, *s;
+ size_t len, nlen;
+ ngx_uint_t ident;
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *query;
+
+ nlen = name->len ? (1 + name->len + 1) : 1;
+
+ len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
+
+ p = ngx_resolver_alloc(r, len);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ rn->qlen = (u_short) len;
+ rn->query = p;
+
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "resolve: \"%V\" SRV %i", name, ident & 0xffff);
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ /* recursion query */
+ query->flags_hi = 1; query->flags_lo = 0;
+
+ /* one question */
+ query->nqs_hi = 0; query->nqs_lo = 1;
+ query->nan_hi = 0; query->nan_lo = 0;
+ query->nns_hi = 0; query->nns_lo = 0;
+ query->nar_hi = 0; query->nar_lo = 0;
+
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
+
+ qs = (ngx_resolver_qs_t *) p;
+
+ /* query type */
+ qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV;
+
+ /* IN query class */
+ qs->class_hi = 0; qs->class_lo = 1;
+
+ /* converts "www.example.com" to "\3www\7example\3com\0" */
+
+ len = 0;
+ p--;
+ *p-- = '\0';
+
+ if (name->len == 0) {
+ return NGX_DECLINED;
+ }
+
+ for (s = name->data + name->len - 1; s >= name->data; s--) {
+ if (*s != '.') {
+ *p = *s;
+ len++;
+
+ } else {
+ if (len == 0 || len > 255) {
+ return NGX_DECLINED;
+ }
+
+ *p = (u_char) len;
+ len = 0;
+ }
+
+ p--;
+ }
+
+ if (len == 0 || len > 255) {
+ return NGX_DECLINED;
+ }
+
+ *p = (u_char) len;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_resolver_addr_t *addr)
+{
+ u_char *p, *d;
+ size_t len;
+ in_addr_t inaddr;
+ ngx_int_t n;
+ ngx_uint_t ident;
+ ngx_resolver_hdr_t *query;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (addr->sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ len = sizeof(ngx_resolver_hdr_t)
+ + 64 + sizeof(".ip6.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ len = sizeof(ngx_resolver_hdr_t)
+ + sizeof(".255.255.255.255.in-addr.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+ }
+
+ p = ngx_resolver_alloc(r, len);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ rn->query = p;
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ /* recursion query */
+ query->flags_hi = 1; query->flags_lo = 0;
+
+ /* one question */
+ query->nqs_hi = 0; query->nqs_lo = 1;
+ query->nan_hi = 0; query->nan_lo = 0;
+ query->nns_hi = 0; query->nns_lo = 0;
+ query->nar_hi = 0; query->nar_lo = 0;
+
+ p += sizeof(ngx_resolver_hdr_t);
+
+ switch (addr->sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) addr->sockaddr;
+
+ for (n = 15; n >= 0; n--) {
+ p = ngx_sprintf(p, "\1%xd\1%xd",
+ sin6->sin6_addr.s6_addr[n] & 0xf,
+ (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
+ }
+
+ p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
+
+ break;
+#endif
+
+ default: /* AF_INET */
+
+ sin = (struct sockaddr_in *) addr->sockaddr;
+ inaddr = ntohl(sin->sin_addr.s_addr);
+
+ for (n = 0; n < 32; n += 8) {
+ d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
+ *p = (u_char) (d - &p[1]);
+ p = d;
+ }
+
+ p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
+ }
+
+ /* query type "PTR", IN query class */
+ p = ngx_cpymem(p, "\0\14\0\1", 4);
+
+ rn->qlen = (u_short) (p - rn->query);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
+ u_char *last)
+{
+ char *err;
+ u_char *p, *dst;
+ ssize_t len;
+ ngx_uint_t i, n;
+
+ p = src;
+ len = -1;
+
+ /*
+ * compression pointers allow to create endless loop, so we set limit;
+ * 128 pointers should be enough to store 255-byte name
+ */
+
+ for (i = 0; i < 128; i++) {
+ n = *p++;
+
+ if (n == 0) {
+ goto done;
+ }
+
+ if (n & 0xc0) {
+ n = ((n & 0x3f) << 8) + *p;
+ p = &buf[n];
+
+ } else {
+ len += 1 + n;
+ p = &p[n];
+ }
+
+ if (p >= last) {
+ err = "name is out of response";
+ goto invalid;
+ }
+ }
+
+ err = "compression pointers loop";
+
+invalid:
+
+ ngx_log_error(r->log_level, r->log, 0, err);
+
+ return NGX_ERROR;
+
+done:
+
+ if (name == NULL) {
+ return NGX_OK;
+ }
+
+ if (len == -1) {
+ ngx_str_null(name);
+ return NGX_OK;
+ }
+
+ dst = ngx_resolver_alloc(r, len);
+ if (dst == NULL) {
+ return NGX_ERROR;
+ }
+
+ name->data = dst;
+
+ n = *src++;
+
+ for ( ;; ) {
+ if (n & 0xc0) {
+ n = ((n & 0x3f) << 8) + *src;
+ src = &buf[n];
+
+ n = *src++;
+
+ } else {
+ ngx_strlow(dst, src, n);
+ dst += n;
+ src += n;
+
+ n = *src++;
+
+ if (n != 0) {
+ *dst++ = '.';
+ }
+ }
+
+ if (n == 0) {
+ name->len = dst - name->data;
+ return NGX_OK;
+ }
+ }
+}
+
+
+static void
+ngx_resolver_timeout_handler(ngx_event_t *ev)
+{
+ ngx_resolver_ctx_t *ctx;
+
+ ctx = ev->data;
+
+ ctx->state = NGX_RESOLVE_TIMEDOUT;
+
+ ctx->handler(ctx);
+}
+
+
+static void
+ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
+{
+ ngx_uint_t i;
+
+ /* lock alloc mutex */
+
+ if (rn->query) {
+ ngx_resolver_free_locked(r, rn->query);
+ }
+
+ if (rn->name) {
+ ngx_resolver_free_locked(r, rn->name);
+ }
+
+ if (rn->cnlen) {
+ ngx_resolver_free_locked(r, rn->u.cname);
+ }
+
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u.addrs);
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
+ if (rn->nsrvs) {
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
+ if (rn->u.srvs[i].name.data) {
+ ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
+ }
+ }
+
+ ngx_resolver_free_locked(r, rn->u.srvs);
+ }
+
+ ngx_resolver_free_locked(r, rn);
+
+ /* unlock alloc mutex */
+}
+
+
+static void *
+ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
+{
+ u_char *p;
+
+ /* lock alloc mutex */
+
+ p = ngx_alloc(size, r->log);
+
+ /* unlock alloc mutex */
+
+ return p;
+}
+
+
+static void *
+ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
+{
+ u_char *p;
+
+ p = ngx_resolver_alloc(r, size);
+
+ if (p) {
+ ngx_memzero(p, size);
+ }
+
+ return p;
+}
+
+
+static void
+ngx_resolver_free(ngx_resolver_t *r, void *p)
+{
+ /* lock alloc mutex */
+
+ ngx_free(p);
+
+ /* unlock alloc mutex */
+}
+
+
+static void
+ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
+{
+ ngx_free(p);
+}
+
+
+static void *
+ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
+{
+ void *dst;
+
+ dst = ngx_resolver_alloc(r, size);
+
+ if (dst == NULL) {
+ return dst;
+ }
+
+ ngx_memcpy(dst, src, size);
+
+ return dst;
+}
+
+
+static ngx_resolver_addr_t *
+ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_uint_t rotate)
+{
+ ngx_uint_t d, i, j, n;
+ in_addr_t *addr;
+ ngx_sockaddr_t *sockaddr;
+ struct sockaddr_in *sin;
+ ngx_resolver_addr_t *dst;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+ struct sockaddr_in6 *sin6;
+#endif
+
+ n = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ n += rn->naddrs6;
+#endif
+
+ dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t));
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ sockaddr = ngx_resolver_calloc(r, n * sizeof(ngx_sockaddr_t));
+ if (sockaddr == NULL) {
+ ngx_resolver_free(r, dst);
+ return NULL;
+ }
+
+ i = 0;
+ d = rotate ? ngx_random() % n : 0;
+
+ if (rn->naddrs) {
+ j = rotate ? ngx_random() % rn->naddrs : 0;
+
+ addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
+
+ do {
+ sin = &sockaddr[d].sockaddr_in;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr[j++];
+ dst[d].sockaddr = (struct sockaddr *) sin;
+ dst[d++].socklen = sizeof(struct sockaddr_in);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == (ngx_uint_t) rn->naddrs) {
+ j = 0;
+ }
+ } while (++i < (ngx_uint_t) rn->naddrs);
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6) {
+ j = rotate ? ngx_random() % rn->naddrs6 : 0;
+
+ addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
+
+ do {
+ sin6 = &sockaddr[d].sockaddr_in6;
+ sin6->sin6_family = AF_INET6;
+ ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
+ dst[d].sockaddr = (struct sockaddr *) sin6;
+ dst[d++].socklen = sizeof(struct sockaddr_in6);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == rn->naddrs6) {
+ j = 0;
+ }
+ } while (++i < n);
+ }
+#endif
+
+ return dst;
+}
+
+
+static void
+ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
+{
+ ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w;
+ ngx_resolver_addr_t *addrs;
+ ngx_resolver_srv_name_t *srvs;
+
+ naddrs = 0;
+
+ for (i = 0; i < ctx->nsrvs; i++) {
+ naddrs += ctx->srvs[i].naddrs;
+ }
+
+ if (naddrs == 0) {
+ ctx->state = NGX_RESOLVE_NXDOMAIN;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+ ctx->handler(ctx);
+ return;
+ }
+
+ addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t));
+ if (addrs == NULL) {
+ ctx->state = NGX_ERROR;
+ ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
+
+ ctx->handler(ctx);
+ return;
+ }
+
+ srvs = ctx->srvs;
+ nsrvs = ctx->nsrvs;
+
+ i = 0;
+ n = 0;
+
+ do {
+ nw = 0;
+
+ for (j = i; j < nsrvs; j++) {
+ if (srvs[j].priority != srvs[i].priority) {
+ break;
+ }
+
+ nw += srvs[j].naddrs * srvs[j].weight;
+ }
+
+ if (nw == 0) {
+ goto next_srv;
+ }
+
+ w = ngx_random() % nw;
+
+ for (k = i; k < j; k++) {
+ if (w < srvs[k].naddrs * srvs[k].weight) {
+ break;
+ }
+
+ w -= srvs[k].naddrs * srvs[k].weight;
+ }
+
+ for (l = i; l < j; l++) {
+
+ for (m = 0; m < srvs[k].naddrs; m++) {
+ addrs[n].socklen = srvs[k].addrs[m].socklen;
+ addrs[n].sockaddr = srvs[k].addrs[m].sockaddr;
+ addrs[n].name = srvs[k].name;
+ addrs[n].priority = srvs[k].priority;
+ addrs[n].weight = srvs[k].weight;
+ n++;
+ }
+
+ if (++k == j) {
+ k = i;
+ }
+ }
+
+next_srv:
+
+ i = j;
+
+ } while (i < ctx->nsrvs);
+
+ ctx->state = NGX_OK;
+ ctx->addrs = addrs;
+ ctx->naddrs = naddrs;
+
+ ctx->handler(ctx);
+
+ ngx_resolver_free(r, addrs);
+}
+
+
+char *
+ngx_resolver_strerror(ngx_int_t err)
+{
+ static char *errors[] = {
+ "Format error", /* FORMERR */
+ "Server failure", /* SERVFAIL */
+ "Host not found", /* NXDOMAIN */
+ "Unimplemented", /* NOTIMP */
+ "Operation refused" /* REFUSED */
+ };
+
+ if (err > 0 && err < 6) {
+ return errors[err - 1];
+ }
+
+ if (err == NGX_RESOLVE_TIMEDOUT) {
+ return "Operation timed out";
+ }
+
+ return "Unknown error";
+}
+
+
+static u_char *
+ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
+{
+ u_char *p;
+ ngx_resolver_connection_t *rec;
+
+ p = buf;
+
+ if (log->action) {
+ p = ngx_snprintf(buf, len, " while %s", log->action);
+ len -= p - buf;
+ }
+
+ rec = log->data;
+
+ if (rec) {
+ p = ngx_snprintf(p, len, ", resolver: %V", &rec->server);
+ }
+
+ return p;
+}
+
+
+static ngx_int_t
+ngx_udp_connect(ngx_resolver_connection_t *rec)
+{
+ int rc;
+ ngx_int_t event;
+ ngx_event_t *rev, *wev;
+ ngx_socket_t s;
+ ngx_connection_t *c;
+
+ s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s);
+
+ if (s == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ c = ngx_get_connection(s, &rec->log);
+
+ if (c == NULL) {
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_close_socket_n "failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (ngx_nonblocking(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_nonblocking_n " failed");
+
+ goto failed;
+ }
+
+ rev = c->read;
+ wev = c->write;
+
+ rev->log = &rec->log;
+ wev->log = &rec->log;
+
+ rec->udp = c;
+
+ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
+ "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
+
+ rc = connect(s, rec->sockaddr, rec->socklen);
+
+ /* TODO: iocp */
+
+ if (rc == -1) {
+ ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno,
+ "connect() failed");
+
+ goto failed;
+ }
+
+ /* UDP sockets are always ready to write */
+ wev->ready = 1;
+
+ event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
+ /* kqueue, epoll */ NGX_CLEAR_EVENT:
+ /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
+ /* eventport event type has no meaning: oneshot only */
+
+ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
+ goto failed;
+ }
+
+ return NGX_OK;
+
+failed:
+
+ ngx_close_connection(c);
+ rec->udp = NULL;
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_tcp_connect(ngx_resolver_connection_t *rec)
+{
+ int rc;
+ ngx_int_t event;
+ ngx_err_t err;
+ ngx_uint_t level;
+ ngx_socket_t s;
+ ngx_event_t *rev, *wev;
+ ngx_connection_t *c;
+
+ s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
+
+ if (s == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ c = ngx_get_connection(s, &rec->log);
+
+ if (c == NULL) {
+ if (ngx_close_socket(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_close_socket_n "failed");
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (ngx_nonblocking(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_nonblocking_n " failed");
+
+ goto failed;
+ }
+
+ rev = c->read;
+ wev = c->write;
+
+ rev->log = &rec->log;
+ wev->log = &rec->log;
+
+ rec->tcp = c;
+
+ c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
+
+ if (ngx_add_conn) {
+ if (ngx_add_conn(c) == NGX_ERROR) {
+ goto failed;
+ }
+ }
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
+ "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
+
+ rc = connect(s, rec->sockaddr, rec->socklen);
+
+ if (rc == -1) {
+ err = ngx_socket_errno;
+
+
+ if (err != NGX_EINPROGRESS
+#if (NGX_WIN32)
+ /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
+ && err != NGX_EAGAIN
+#endif
+ )
+ {
+ if (err == NGX_ECONNREFUSED
+#if (NGX_LINUX)
+ /*
+ * Linux returns EAGAIN instead of ECONNREFUSED
+ * for unix sockets if listen queue is full
+ */
+ || err == NGX_EAGAIN
+#endif
+ || err == NGX_ECONNRESET
+ || err == NGX_ENETDOWN
+ || err == NGX_ENETUNREACH
+ || err == NGX_EHOSTDOWN
+ || err == NGX_EHOSTUNREACH)
+ {
+ level = NGX_LOG_ERR;
+
+ } else {
+ level = NGX_LOG_CRIT;
+ }
+
+ ngx_log_error(level, c->log, err, "connect() to %V failed",
+ &rec->server);
+
+ ngx_close_connection(c);
+ rec->tcp = NULL;
+
+ return NGX_ERROR;
+ }
+ }
+
+ if (ngx_add_conn) {
+ if (rc == -1) {
+
+ /* NGX_EINPROGRESS */
+
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
+
+ wev->ready = 1;
+
+ return NGX_OK;
+ }
+
+ if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
+ "connect(): %d", rc);
+
+ if (ngx_blocking(s) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
+ ngx_blocking_n " failed");
+ goto failed;
+ }
+
+ /*
+ * FreeBSD's aio allows to post an operation on non-connected socket.
+ * NT does not support it.
+ *
+ * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
+ */
+
+ rev->ready = 1;
+ wev->ready = 1;
+
+ return NGX_OK;
+ }
+
+ if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
+
+ /* kqueue */
+
+ event = NGX_CLEAR_EVENT;
+
+ } else {
+
+ /* select, poll, /dev/poll */
+
+ event = NGX_LEVEL_EVENT;
+ }
+
+ if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
+ goto failed;
+ }
+
+ if (rc == -1) {
+
+ /* NGX_EINPROGRESS */
+
+ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
+ goto failed;
+ }
+
+ return NGX_AGAIN;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
+
+ wev->ready = 1;
+
+ return NGX_OK;
+
+failed:
+
+ ngx_close_connection(c);
+ rec->tcp = NULL;
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_resolver_cmp_srvs(const void *one, const void *two)
+{
+ ngx_int_t p1, p2;
+ ngx_resolver_srv_t *first, *second;
+
+ first = (ngx_resolver_srv_t *) one;
+ second = (ngx_resolver_srv_t *) two;
+
+ p1 = first->priority;
+ p2 = second->priority;
+
+ return p1 - p2;
+}
diff --git a/app/nginx/src/core/ngx_resolver.h b/app/nginx/src/core/ngx_resolver.h
new file mode 100644
index 0000000..a0d6fc3
--- /dev/null
+++ b/app/nginx/src/core/ngx_resolver.h
@@ -0,0 +1,238 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#ifndef _NGX_RESOLVER_H_INCLUDED_
+#define _NGX_RESOLVER_H_INCLUDED_
+
+
+#define NGX_RESOLVE_A 1
+#define NGX_RESOLVE_CNAME 5
+#define NGX_RESOLVE_PTR 12
+#define NGX_RESOLVE_MX 15
+#define NGX_RESOLVE_TXT 16
+#if (NGX_HAVE_INET6)
+#define NGX_RESOLVE_AAAA 28
+#endif
+#define NGX_RESOLVE_SRV 33
+#define NGX_RESOLVE_DNAME 39
+
+#define NGX_RESOLVE_FORMERR 1
+#define NGX_RESOLVE_SERVFAIL 2
+#define NGX_RESOLVE_NXDOMAIN 3
+#define NGX_RESOLVE_NOTIMP 4
+#define NGX_RESOLVE_REFUSED 5
+#define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT
+
+
+#define NGX_NO_RESOLVER (void *) -1
+
+#define NGX_RESOLVER_MAX_RECURSION 50
+
+
+typedef struct ngx_resolver_s ngx_resolver_t;
+
+
+typedef struct {
+ ngx_connection_t *udp;
+ ngx_connection_t *tcp;
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t server;
+ ngx_log_t log;
+ ngx_buf_t *read_buf;
+ ngx_buf_t *write_buf;
+ ngx_resolver_t *resolver;
+} ngx_resolver_connection_t;
+
+
+typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t;
+
+typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx);
+
+
+typedef struct {
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t name;
+ u_short priority;
+ u_short weight;
+} ngx_resolver_addr_t;
+
+
+typedef struct {
+ ngx_str_t name;
+ u_short priority;
+ u_short weight;
+ u_short port;
+} ngx_resolver_srv_t;
+
+
+typedef struct {
+ ngx_str_t name;
+ u_short priority;
+ u_short weight;
+ u_short port;
+
+ ngx_resolver_ctx_t *ctx;
+ ngx_int_t state;
+
+ ngx_uint_t naddrs;
+ ngx_addr_t *addrs;
+} ngx_resolver_srv_name_t;
+
+
+typedef struct {
+ ngx_rbtree_node_t node;
+ ngx_queue_t queue;
+
+ /* PTR: resolved name, A: name to resolve */
+ u_char *name;
+
+#if (NGX_HAVE_INET6)
+ /* PTR: IPv6 address to resolve (IPv4 address is in rbtree node key) */
+ struct in6_addr addr6;
+#endif
+
+ u_short nlen;
+ u_short qlen;
+
+ u_char *query;
+#if (NGX_HAVE_INET6)
+ u_char *query6;
+#endif
+
+ union {
+ in_addr_t addr;
+ in_addr_t *addrs;
+ u_char *cname;
+ ngx_resolver_srv_t *srvs;
+ } u;
+
+ u_char code;
+ u_short naddrs;
+ u_short nsrvs;
+ u_short cnlen;
+
+#if (NGX_HAVE_INET6)
+ union {
+ struct in6_addr addr6;
+ struct in6_addr *addrs6;
+ } u6;
+
+ u_short naddrs6;
+#endif
+
+ time_t expire;
+ time_t valid;
+ uint32_t ttl;
+
+ unsigned tcp:1;
+#if (NGX_HAVE_INET6)
+ unsigned tcp6:1;
+#endif
+
+ ngx_uint_t last_connection;
+
+ ngx_resolver_ctx_t *waiting;
+} ngx_resolver_node_t;
+
+
+struct ngx_resolver_s {
+ /* has to be pointer because of "incomplete type" */
+ ngx_event_t *event;
+ void *dummy;
+ ngx_log_t *log;
+
+ /* event ident must be after 3 pointers as in ngx_connection_t */
+ ngx_int_t ident;
+
+ /* simple round robin DNS peers balancer */
+ ngx_array_t connections;
+ ngx_uint_t last_connection;
+
+ ngx_rbtree_t name_rbtree;
+ ngx_rbtree_node_t name_sentinel;
+
+ ngx_rbtree_t srv_rbtree;
+ ngx_rbtree_node_t srv_sentinel;
+
+ ngx_rbtree_t addr_rbtree;
+ ngx_rbtree_node_t addr_sentinel;
+
+ ngx_queue_t name_resend_queue;
+ ngx_queue_t srv_resend_queue;
+ ngx_queue_t addr_resend_queue;
+
+ ngx_queue_t name_expire_queue;
+ ngx_queue_t srv_expire_queue;
+ ngx_queue_t addr_expire_queue;
+
+#if (NGX_HAVE_INET6)
+ ngx_uint_t ipv6; /* unsigned ipv6:1; */
+ ngx_rbtree_t addr6_rbtree;
+ ngx_rbtree_node_t addr6_sentinel;
+ ngx_queue_t addr6_resend_queue;
+ ngx_queue_t addr6_expire_queue;
+#endif
+
+ time_t resend_timeout;
+ time_t tcp_timeout;
+ time_t expire;
+ time_t valid;
+
+ ngx_uint_t log_level;
+};
+
+
+struct ngx_resolver_ctx_s {
+ ngx_resolver_ctx_t *next;
+ ngx_resolver_t *resolver;
+ ngx_resolver_node_t *node;
+
+ /* event ident must be after 3 pointers as in ngx_connection_t */
+ ngx_int_t ident;
+
+ ngx_int_t state;
+ ngx_str_t name;
+ ngx_str_t service;
+
+ time_t valid;
+ ngx_uint_t naddrs;
+ ngx_resolver_addr_t *addrs;
+ ngx_resolver_addr_t addr;
+ struct sockaddr_in sin;
+
+ ngx_uint_t count;
+ ngx_uint_t nsrvs;
+ ngx_resolver_srv_name_t *srvs;
+
+ ngx_resolver_handler_pt handler;
+ void *data;
+ ngx_msec_t timeout;
+
+ ngx_uint_t quick; /* unsigned quick:1; */
+ ngx_uint_t recursion;
+ ngx_event_t *event;
+};
+
+
+ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names,
+ ngx_uint_t n);
+ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
+ ngx_resolver_ctx_t *temp);
+ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
+void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx);
+ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx);
+void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx);
+char *ngx_resolver_strerror(ngx_int_t err);
+
+
+#endif /* _NGX_RESOLVER_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_rwlock.c b/app/nginx/src/core/ngx_rwlock.c
new file mode 100644
index 0000000..905de78
--- /dev/null
+++ b/app/nginx/src/core/ngx_rwlock.c
@@ -0,0 +1,120 @@
+
+/*
+ * Copyright (C) Ruslan Ermilov
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+
+#define NGX_RWLOCK_SPIN 2048
+#define NGX_RWLOCK_WLOCK ((ngx_atomic_uint_t) -1)
+
+
+void
+ngx_rwlock_wlock(ngx_atomic_t *lock)
+{
+ ngx_uint_t i, n;
+
+ for ( ;; ) {
+
+ if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) {
+ return;
+ }
+
+ if (ngx_ncpu > 1) {
+
+ for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
+
+ for (i = 0; i < n; i++) {
+ ngx_cpu_pause();
+ }
+
+ if (*lock == 0
+ && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK))
+ {
+ return;
+ }
+ }
+ }
+
+ ngx_sched_yield();
+ }
+}
+
+
+void
+ngx_rwlock_rlock(ngx_atomic_t *lock)
+{
+ ngx_uint_t i, n;
+ ngx_atomic_uint_t readers;
+
+ for ( ;; ) {
+ readers = *lock;
+
+ if (readers != NGX_RWLOCK_WLOCK
+ && ngx_atomic_cmp_set(lock, readers, readers + 1))
+ {
+ return;
+ }
+
+ if (ngx_ncpu > 1) {
+
+ for (n = 1; n < NGX_RWLOCK_SPIN; n <<= 1) {
+
+ for (i = 0; i < n; i++) {
+ ngx_cpu_pause();
+ }
+
+ readers = *lock;
+
+ if (readers != NGX_RWLOCK_WLOCK
+ && ngx_atomic_cmp_set(lock, readers, readers + 1))
+ {
+ return;
+ }
+ }
+ }
+
+ ngx_sched_yield();
+ }
+}
+
+
+void
+ngx_rwlock_unlock(ngx_atomic_t *lock)
+{
+ ngx_atomic_uint_t readers;
+
+ readers = *lock;
+
+ if (readers == NGX_RWLOCK_WLOCK) {
+ *lock = 0;
+ return;
+ }
+
+ for ( ;; ) {
+
+ if (ngx_atomic_cmp_set(lock, readers, readers - 1)) {
+ return;
+ }
+
+ readers = *lock;
+ }
+}
+
+
+#else
+
+#if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE)
+
+#error ngx_atomic_cmp_set() is not defined!
+
+#endif
+
+#endif
diff --git a/app/nginx/src/core/ngx_rwlock.h b/app/nginx/src/core/ngx_rwlock.h
new file mode 100644
index 0000000..8b16eca
--- /dev/null
+++ b/app/nginx/src/core/ngx_rwlock.h
@@ -0,0 +1,21 @@
+
+/*
+ * Copyright (C) Ruslan Ermilov
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_RWLOCK_H_INCLUDED_
+#define _NGX_RWLOCK_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void ngx_rwlock_wlock(ngx_atomic_t *lock);
+void ngx_rwlock_rlock(ngx_atomic_t *lock);
+void ngx_rwlock_unlock(ngx_atomic_t *lock);
+
+
+#endif /* _NGX_RWLOCK_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_sha1.c b/app/nginx/src/core/ngx_sha1.c
new file mode 100644
index 0000000..f00dc52
--- /dev/null
+++ b/app/nginx/src/core/ngx_sha1.c
@@ -0,0 +1,294 @@
+
+/*
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ *
+ * An internal SHA1 implementation.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_sha1.h>
+
+
+static const u_char *ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data,
+ size_t size);
+
+
+void
+ngx_sha1_init(ngx_sha1_t *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->e = 0xc3d2e1f0;
+
+ ctx->bytes = 0;
+}
+
+
+void
+ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+ ctx->bytes += size;
+
+ if (used) {
+ free = 64 - used;
+
+ if (size < free) {
+ ngx_memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ ngx_memcpy(&ctx->buffer[used], data, free);
+ data = (u_char *) data + free;
+ size -= free;
+ (void) ngx_sha1_body(ctx, ctx->buffer, 64);
+ }
+
+ if (size >= 64) {
+ data = ngx_sha1_body(ctx, data, size & ~(size_t) 0x3f);
+ size &= 0x3f;
+ }
+
+ ngx_memcpy(ctx->buffer, data, size);
+}
+
+
+void
+ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx)
+{
+ size_t used, free;
+
+ used = (size_t) (ctx->bytes & 0x3f);
+
+ ctx->buffer[used++] = 0x80;
+
+ free = 64 - used;
+
+ if (free < 8) {
+ ngx_memzero(&ctx->buffer[used], free);
+ (void) ngx_sha1_body(ctx, ctx->buffer, 64);
+ used = 0;
+ free = 64;
+ }
+
+ ngx_memzero(&ctx->buffer[used], free - 8);
+
+ ctx->bytes <<= 3;
+ ctx->buffer[56] = (u_char) (ctx->bytes >> 56);
+ ctx->buffer[57] = (u_char) (ctx->bytes >> 48);
+ ctx->buffer[58] = (u_char) (ctx->bytes >> 40);
+ ctx->buffer[59] = (u_char) (ctx->bytes >> 32);
+ ctx->buffer[60] = (u_char) (ctx->bytes >> 24);
+ ctx->buffer[61] = (u_char) (ctx->bytes >> 16);
+ ctx->buffer[62] = (u_char) (ctx->bytes >> 8);
+ ctx->buffer[63] = (u_char) ctx->bytes;
+
+ (void) ngx_sha1_body(ctx, ctx->buffer, 64);
+
+ result[0] = (u_char) (ctx->a >> 24);
+ result[1] = (u_char) (ctx->a >> 16);
+ result[2] = (u_char) (ctx->a >> 8);
+ result[3] = (u_char) ctx->a;
+ result[4] = (u_char) (ctx->b >> 24);
+ result[5] = (u_char) (ctx->b >> 16);
+ result[6] = (u_char) (ctx->b >> 8);
+ result[7] = (u_char) ctx->b;
+ result[8] = (u_char) (ctx->c >> 24);
+ result[9] = (u_char) (ctx->c >> 16);
+ result[10] = (u_char) (ctx->c >> 8);
+ result[11] = (u_char) ctx->c;
+ result[12] = (u_char) (ctx->d >> 24);
+ result[13] = (u_char) (ctx->d >> 16);
+ result[14] = (u_char) (ctx->d >> 8);
+ result[15] = (u_char) ctx->d;
+ result[16] = (u_char) (ctx->e >> 24);
+ result[17] = (u_char) (ctx->e >> 16);
+ result[18] = (u_char) (ctx->e >> 8);
+ result[19] = (u_char) ctx->e;
+
+ ngx_memzero(ctx, sizeof(*ctx));
+}
+
+
+/*
+ * Helper functions.
+ */
+
+#define ROTATE(bits, word) (((word) << (bits)) | ((word) >> (32 - (bits))))
+
+#define F1(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
+#define F2(b, c, d) ((b) ^ (c) ^ (d))
+#define F3(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
+
+#define STEP(f, a, b, c, d, e, w, t) \
+ temp = ROTATE(5, (a)) + f((b), (c), (d)) + (e) + (w) + (t); \
+ (e) = (d); \
+ (d) = (c); \
+ (c) = ROTATE(30, (b)); \
+ (b) = (a); \
+ (a) = temp;
+
+
+/*
+ * GET() reads 4 input bytes in big-endian byte order and returns
+ * them as uint32_t.
+ */
+
+#define GET(n) \
+ ((uint32_t) p[n * 4 + 3] | \
+ ((uint32_t) p[n * 4 + 2] << 8) | \
+ ((uint32_t) p[n * 4 + 1] << 16) | \
+ ((uint32_t) p[n * 4] << 24))
+
+
+/*
+ * This processes one or more 64-byte data blocks, but does not update
+ * the bit counters. There are no alignment requirements.
+ */
+
+static const u_char *
+ngx_sha1_body(ngx_sha1_t *ctx, const u_char *data, size_t size)
+{
+ uint32_t a, b, c, d, e, temp;
+ uint32_t saved_a, saved_b, saved_c, saved_d, saved_e;
+ uint32_t words[80];
+ ngx_uint_t i;
+ const u_char *p;
+
+ p = data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+ e = ctx->e;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+ saved_e = e;
+
+ /* Load data block into the words array */
+
+ for (i = 0; i < 16; i++) {
+ words[i] = GET(i);
+ }
+
+ for (i = 16; i < 80; i++) {
+ words[i] = ROTATE(1, words[i - 3] ^ words[i - 8] ^ words[i - 14]
+ ^ words[i - 16]);
+ }
+
+ /* Transformations */
+
+ STEP(F1, a, b, c, d, e, words[0], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[1], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[2], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[3], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[4], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[5], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[6], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[7], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[8], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[9], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[10], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[11], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[12], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[13], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[14], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[15], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[16], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[17], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[18], 0x5a827999);
+ STEP(F1, a, b, c, d, e, words[19], 0x5a827999);
+
+ STEP(F2, a, b, c, d, e, words[20], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[21], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[22], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[23], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[24], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[25], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[26], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[27], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[28], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[29], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[30], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[31], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[32], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[33], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[34], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[35], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[36], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[37], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[38], 0x6ed9eba1);
+ STEP(F2, a, b, c, d, e, words[39], 0x6ed9eba1);
+
+ STEP(F3, a, b, c, d, e, words[40], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[41], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[42], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[43], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[44], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[45], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[46], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[47], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[48], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[49], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[50], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[51], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[52], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[53], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[54], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[55], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[56], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[57], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[58], 0x8f1bbcdc);
+ STEP(F3, a, b, c, d, e, words[59], 0x8f1bbcdc);
+
+ STEP(F2, a, b, c, d, e, words[60], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[61], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[62], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[63], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[64], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[65], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[66], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[67], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[68], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[69], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[70], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[71], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[72], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[73], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[74], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[75], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[76], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[77], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[78], 0xca62c1d6);
+ STEP(F2, a, b, c, d, e, words[79], 0xca62c1d6);
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+ e += saved_e;
+
+ p += 64;
+
+ } while (size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+ ctx->e = e;
+
+ return p;
+}
diff --git a/app/nginx/src/core/ngx_sha1.h b/app/nginx/src/core/ngx_sha1.h
new file mode 100644
index 0000000..4a98f71
--- /dev/null
+++ b/app/nginx/src/core/ngx_sha1.h
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SHA1_H_INCLUDED_
+#define _NGX_SHA1_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ uint64_t bytes;
+ uint32_t a, b, c, d, e, f;
+ u_char buffer[64];
+} ngx_sha1_t;
+
+
+void ngx_sha1_init(ngx_sha1_t *ctx);
+void ngx_sha1_update(ngx_sha1_t *ctx, const void *data, size_t size);
+void ngx_sha1_final(u_char result[20], ngx_sha1_t *ctx);
+
+
+#endif /* _NGX_SHA1_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_shmtx.c b/app/nginx/src/core/ngx_shmtx.c
new file mode 100644
index 0000000..a255903
--- /dev/null
+++ b/app/nginx/src/core/ngx_shmtx.c
@@ -0,0 +1,310 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+
+static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
+
+
+ngx_int_t
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
+{
+ mtx->lock = &addr->lock;
+
+ if (mtx->spin == (ngx_uint_t) -1) {
+ return NGX_OK;
+ }
+
+ mtx->spin = 2048;
+
+#if (NGX_HAVE_POSIX_SEM)
+
+ mtx->wait = &addr->wait;
+
+ if (sem_init(&mtx->sem, 1, 0) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_init() failed");
+ } else {
+ mtx->semaphore = 1;
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+void
+ngx_shmtx_destroy(ngx_shmtx_t *mtx)
+{
+#if (NGX_HAVE_POSIX_SEM)
+
+ if (mtx->semaphore) {
+ if (sem_destroy(&mtx->sem) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_destroy() failed");
+ }
+ }
+
+#endif
+}
+
+
+ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+ return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
+}
+
+
+void
+ngx_shmtx_lock(ngx_shmtx_t *mtx)
+{
+ ngx_uint_t i, n;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
+
+ for ( ;; ) {
+
+ if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
+ return;
+ }
+
+ if (ngx_ncpu > 1) {
+
+ for (n = 1; n < mtx->spin; n <<= 1) {
+
+ for (i = 0; i < n; i++) {
+ ngx_cpu_pause();
+ }
+
+ if (*mtx->lock == 0
+ && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
+ {
+ return;
+ }
+ }
+ }
+
+#if (NGX_HAVE_POSIX_SEM)
+
+ if (mtx->semaphore) {
+ (void) ngx_atomic_fetch_add(mtx->wait, 1);
+
+ if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
+ (void) ngx_atomic_fetch_add(mtx->wait, -1);
+ return;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx wait %uA", *mtx->wait);
+
+ while (sem_wait(&mtx->sem) == -1) {
+ ngx_err_t err;
+
+ err = ngx_errno;
+
+ if (err != NGX_EINTR) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+ "sem_wait() failed while waiting on shmtx");
+ break;
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx awoke");
+
+ continue;
+ }
+
+#endif
+
+ ngx_sched_yield();
+ }
+}
+
+
+void
+ngx_shmtx_unlock(ngx_shmtx_t *mtx)
+{
+ if (mtx->spin != (ngx_uint_t) -1) {
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
+ }
+
+ if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
+ ngx_shmtx_wakeup(mtx);
+ }
+}
+
+
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx forced unlock");
+
+ if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
+ ngx_shmtx_wakeup(mtx);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void
+ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
+{
+#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_uint_t wait;
+
+ if (!mtx->semaphore) {
+ return;
+ }
+
+ for ( ;; ) {
+
+ wait = *mtx->wait;
+
+ if ((ngx_atomic_int_t) wait <= 0) {
+ return;
+ }
+
+ if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
+ break;
+ }
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "shmtx wake %uA", wait);
+
+ if (sem_post(&mtx->sem) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ "sem_post() failed while wake shmtx");
+ }
+
+#endif
+}
+
+
+#else
+
+
+ngx_int_t
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
+{
+ if (mtx->name) {
+
+ if (ngx_strcmp(name, mtx->name) == 0) {
+ mtx->name = name;
+ return NGX_OK;
+ }
+
+ ngx_shmtx_destroy(mtx);
+ }
+
+ mtx->fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS);
+
+ if (mtx->fd == NGX_INVALID_FILE) {
+ ngx_log_error(NGX_LOG_EMERG, ngx_cycle->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", name);
+ return NGX_ERROR;
+ }
+
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed", name);
+ }
+
+ mtx->name = name;
+
+ return NGX_OK;
+}
+
+
+void
+ngx_shmtx_destroy(ngx_shmtx_t *mtx)
+{
+ if (ngx_close_file(mtx->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", mtx->name);
+ }
+}
+
+
+ngx_uint_t
+ngx_shmtx_trylock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_trylock_fd(mtx->fd);
+
+ if (err == 0) {
+ return 1;
+ }
+
+ if (err == NGX_EAGAIN) {
+ return 0;
+ }
+
+#if __osf__ /* Tru64 UNIX */
+
+ if (err == NGX_EACCES) {
+ return 0;
+ }
+
+#endif
+
+ ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
+
+ return 0;
+}
+
+
+void
+ngx_shmtx_lock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_lock_fd(mtx->fd);
+
+ if (err == 0) {
+ return;
+ }
+
+ ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
+}
+
+
+void
+ngx_shmtx_unlock(ngx_shmtx_t *mtx)
+{
+ ngx_err_t err;
+
+ err = ngx_unlock_fd(mtx->fd);
+
+ if (err == 0) {
+ return;
+ }
+
+ ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
+}
+
+
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+ return 0;
+}
+
+#endif
diff --git a/app/nginx/src/core/ngx_shmtx.h b/app/nginx/src/core/ngx_shmtx.h
new file mode 100644
index 0000000..91e11be
--- /dev/null
+++ b/app/nginx/src/core/ngx_shmtx.h
@@ -0,0 +1,49 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SHMTX_H_INCLUDED_
+#define _NGX_SHMTX_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ ngx_atomic_t lock;
+#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_t wait;
+#endif
+} ngx_shmtx_sh_t;
+
+
+typedef struct {
+#if (NGX_HAVE_ATOMIC_OPS)
+ ngx_atomic_t *lock;
+#if (NGX_HAVE_POSIX_SEM)
+ ngx_atomic_t *wait;
+ ngx_uint_t semaphore;
+ sem_t sem;
+#endif
+#else
+ ngx_fd_t fd;
+ u_char *name;
+#endif
+ ngx_uint_t spin;
+} ngx_shmtx_t;
+
+
+ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr,
+ u_char *name);
+void ngx_shmtx_destroy(ngx_shmtx_t *mtx);
+ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
+void ngx_shmtx_lock(ngx_shmtx_t *mtx);
+void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
+ngx_uint_t ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid);
+
+
+#endif /* _NGX_SHMTX_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_slab.c b/app/nginx/src/core/ngx_slab.c
new file mode 100644
index 0000000..1d4ce2b
--- /dev/null
+++ b/app/nginx/src/core/ngx_slab.c
@@ -0,0 +1,806 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#define NGX_SLAB_PAGE_MASK 3
+#define NGX_SLAB_PAGE 0
+#define NGX_SLAB_BIG 1
+#define NGX_SLAB_EXACT 2
+#define NGX_SLAB_SMALL 3
+
+#if (NGX_PTR_SIZE == 4)
+
+#define NGX_SLAB_PAGE_FREE 0
+#define NGX_SLAB_PAGE_BUSY 0xffffffff
+#define NGX_SLAB_PAGE_START 0x80000000
+
+#define NGX_SLAB_SHIFT_MASK 0x0000000f
+#define NGX_SLAB_MAP_MASK 0xffff0000
+#define NGX_SLAB_MAP_SHIFT 16
+
+#define NGX_SLAB_BUSY 0xffffffff
+
+#else /* (NGX_PTR_SIZE == 8) */
+
+#define NGX_SLAB_PAGE_FREE 0
+#define NGX_SLAB_PAGE_BUSY 0xffffffffffffffff
+#define NGX_SLAB_PAGE_START 0x8000000000000000
+
+#define NGX_SLAB_SHIFT_MASK 0x000000000000000f
+#define NGX_SLAB_MAP_MASK 0xffffffff00000000
+#define NGX_SLAB_MAP_SHIFT 32
+
+#define NGX_SLAB_BUSY 0xffffffffffffffff
+
+#endif
+
+
+#define ngx_slab_slots(pool) \
+ (ngx_slab_page_t *) ((u_char *) (pool) + sizeof(ngx_slab_pool_t))
+
+#define ngx_slab_page_type(page) ((page)->prev & NGX_SLAB_PAGE_MASK)
+
+#define ngx_slab_page_prev(page) \
+ (ngx_slab_page_t *) ((page)->prev & ~NGX_SLAB_PAGE_MASK)
+
+#define ngx_slab_page_addr(pool, page) \
+ ((((page) - (pool)->pages) << ngx_pagesize_shift) \
+ + (uintptr_t) (pool)->start)
+
+
+#if (NGX_DEBUG_MALLOC)
+
+#define ngx_slab_junk(p, size) ngx_memset(p, 0xA5, size)
+
+#elif (NGX_HAVE_DEBUG_MALLOC)
+
+#define ngx_slab_junk(p, size) \
+ if (ngx_debug_malloc) ngx_memset(p, 0xA5, size)
+
+#else
+
+#define ngx_slab_junk(p, size)
+
+#endif
+
+static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool,
+ ngx_uint_t pages);
+static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
+ ngx_uint_t pages);
+static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level,
+ char *text);
+
+
+static ngx_uint_t ngx_slab_max_size;
+static ngx_uint_t ngx_slab_exact_size;
+static ngx_uint_t ngx_slab_exact_shift;
+
+
+void
+ngx_slab_init(ngx_slab_pool_t *pool)
+{
+ u_char *p;
+ size_t size;
+ ngx_int_t m;
+ ngx_uint_t i, n, pages;
+ ngx_slab_page_t *slots, *page;
+
+ /* STUB */
+ if (ngx_slab_max_size == 0) {
+ ngx_slab_max_size = ngx_pagesize / 2;
+ ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t));
+ for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) {
+ /* void */
+ }
+ }
+ /**/
+
+ pool->min_size = (size_t) 1 << pool->min_shift;
+
+ slots = ngx_slab_slots(pool);
+
+ p = (u_char *) slots;
+ size = pool->end - p;
+
+ ngx_slab_junk(p, size);
+
+ n = ngx_pagesize_shift - pool->min_shift;
+
+ for (i = 0; i < n; i++) {
+ /* only "next" is used in list head */
+ slots[i].slab = 0;
+ slots[i].next = &slots[i];
+ slots[i].prev = 0;
+ }
+
+ p += n * sizeof(ngx_slab_page_t);
+
+ pool->stats = (ngx_slab_stat_t *) p;
+ ngx_memzero(pool->stats, n * sizeof(ngx_slab_stat_t));
+
+ p += n * sizeof(ngx_slab_stat_t);
+
+ size -= n * (sizeof(ngx_slab_page_t) + sizeof(ngx_slab_stat_t));
+
+ pages = (ngx_uint_t) (size / (ngx_pagesize + sizeof(ngx_slab_page_t)));
+
+ pool->pages = (ngx_slab_page_t *) p;
+ ngx_memzero(pool->pages, pages * sizeof(ngx_slab_page_t));
+
+ page = pool->pages;
+
+ /* only "next" is used in list head */
+ pool->free.slab = 0;
+ pool->free.next = page;
+ pool->free.prev = 0;
+
+ page->slab = pages;
+ page->next = &pool->free;
+ page->prev = (uintptr_t) &pool->free;
+
+ pool->start = ngx_align_ptr(p + pages * sizeof(ngx_slab_page_t),
+ ngx_pagesize);
+
+ m = pages - (pool->end - pool->start) / ngx_pagesize;
+ if (m > 0) {
+ pages -= m;
+ page->slab = pages;
+ }
+
+ pool->last = pool->pages + pages;
+ pool->pfree = pages;
+
+ pool->log_nomem = 1;
+ pool->log_ctx = &pool->zero;
+ pool->zero = '\0';
+}
+
+
+void *
+ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
+{
+ void *p;
+
+ ngx_shmtx_lock(&pool->mutex);
+
+ p = ngx_slab_alloc_locked(pool, size);
+
+ ngx_shmtx_unlock(&pool->mutex);
+
+ return p;
+}
+
+
+void *
+ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
+{
+ size_t s;
+ uintptr_t p, n, m, mask, *bitmap;
+ ngx_uint_t i, slot, shift, map;
+ ngx_slab_page_t *page, *prev, *slots;
+
+ if (size > ngx_slab_max_size) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
+ "slab alloc: %uz", size);
+
+ page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift)
+ + ((size % ngx_pagesize) ? 1 : 0));
+ if (page) {
+ p = ngx_slab_page_addr(pool, page);
+
+ } else {
+ p = 0;
+ }
+
+ goto done;
+ }
+
+ if (size > pool->min_size) {
+ shift = 1;
+ for (s = size - 1; s >>= 1; shift++) { /* void */ }
+ slot = shift - pool->min_shift;
+
+ } else {
+ shift = pool->min_shift;
+ slot = 0;
+ }
+
+ pool->stats[slot].reqs++;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
+ "slab alloc: %uz slot: %ui", size, slot);
+
+ slots = ngx_slab_slots(pool);
+ page = slots[slot].next;
+
+ if (page->next != page) {
+
+ if (shift < ngx_slab_exact_shift) {
+
+ bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
+
+ map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+
+ for (n = 0; n < map; n++) {
+
+ if (bitmap[n] != NGX_SLAB_BUSY) {
+
+ for (m = 1, i = 0; m; m <<= 1, i++) {
+ if (bitmap[n] & m) {
+ continue;
+ }
+
+ bitmap[n] |= m;
+
+ i = (n * sizeof(uintptr_t) * 8 + i) << shift;
+
+ p = (uintptr_t) bitmap + i;
+
+ pool->stats[slot].used++;
+
+ if (bitmap[n] == NGX_SLAB_BUSY) {
+ for (n = n + 1; n < map; n++) {
+ if (bitmap[n] != NGX_SLAB_BUSY) {
+ goto done;
+ }
+ }
+
+ prev = ngx_slab_page_prev(page);
+ prev->next = page->next;
+ page->next->prev = page->prev;
+
+ page->next = NULL;
+ page->prev = NGX_SLAB_SMALL;
+ }
+
+ goto done;
+ }
+ }
+ }
+
+ } else if (shift == ngx_slab_exact_shift) {
+
+ for (m = 1, i = 0; m; m <<= 1, i++) {
+ if (page->slab & m) {
+ continue;
+ }
+
+ page->slab |= m;
+
+ if (page->slab == NGX_SLAB_BUSY) {
+ prev = ngx_slab_page_prev(page);
+ prev->next = page->next;
+ page->next->prev = page->prev;
+
+ page->next = NULL;
+ page->prev = NGX_SLAB_EXACT;
+ }
+
+ p = ngx_slab_page_addr(pool, page) + (i << shift);
+
+ pool->stats[slot].used++;
+
+ goto done;
+ }
+
+ } else { /* shift > ngx_slab_exact_shift */
+
+ mask = ((uintptr_t) 1 << (ngx_pagesize >> shift)) - 1;
+ mask <<= NGX_SLAB_MAP_SHIFT;
+
+ for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0;
+ m & mask;
+ m <<= 1, i++)
+ {
+ if (page->slab & m) {
+ continue;
+ }
+
+ page->slab |= m;
+
+ if ((page->slab & NGX_SLAB_MAP_MASK) == mask) {
+ prev = ngx_slab_page_prev(page);
+ prev->next = page->next;
+ page->next->prev = page->prev;
+
+ page->next = NULL;
+ page->prev = NGX_SLAB_BIG;
+ }
+
+ p = ngx_slab_page_addr(pool, page) + (i << shift);
+
+ pool->stats[slot].used++;
+
+ goto done;
+ }
+ }
+
+ ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_alloc(): page is busy");
+ ngx_debug_point();
+ }
+
+ page = ngx_slab_alloc_pages(pool, 1);
+
+ if (page) {
+ if (shift < ngx_slab_exact_shift) {
+ bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page);
+
+ n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
+
+ if (n == 0) {
+ n = 1;
+ }
+
+ /* "n" elements for bitmap, plus one requested */
+ bitmap[0] = ((uintptr_t) 2 << n) - 1;
+
+ map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+
+ for (i = 1; i < map; i++) {
+ bitmap[i] = 0;
+ }
+
+ page->slab = shift;
+ page->next = &slots[slot];
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
+
+ slots[slot].next = page;
+
+ pool->stats[slot].total += (ngx_pagesize >> shift) - n;
+
+ p = ngx_slab_page_addr(pool, page) + (n << shift);
+
+ pool->stats[slot].used++;
+
+ goto done;
+
+ } else if (shift == ngx_slab_exact_shift) {
+
+ page->slab = 1;
+ page->next = &slots[slot];
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
+
+ slots[slot].next = page;
+
+ pool->stats[slot].total += sizeof(uintptr_t) * 8;
+
+ p = ngx_slab_page_addr(pool, page);
+
+ pool->stats[slot].used++;
+
+ goto done;
+
+ } else { /* shift > ngx_slab_exact_shift */
+
+ page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
+ page->next = &slots[slot];
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
+
+ slots[slot].next = page;
+
+ pool->stats[slot].total += ngx_pagesize >> shift;
+
+ p = ngx_slab_page_addr(pool, page);
+
+ pool->stats[slot].used++;
+
+ goto done;
+ }
+ }
+
+ p = 0;
+
+ pool->stats[slot].fails++;
+
+done:
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
+ "slab alloc: %p", (void *) p);
+
+ return (void *) p;
+}
+
+
+void *
+ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size)
+{
+ void *p;
+
+ ngx_shmtx_lock(&pool->mutex);
+
+ p = ngx_slab_calloc_locked(pool, size);
+
+ ngx_shmtx_unlock(&pool->mutex);
+
+ return p;
+}
+
+
+void *
+ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size)
+{
+ void *p;
+
+ p = ngx_slab_alloc_locked(pool, size);
+ if (p) {
+ ngx_memzero(p, size);
+ }
+
+ return p;
+}
+
+
+void
+ngx_slab_free(ngx_slab_pool_t *pool, void *p)
+{
+ ngx_shmtx_lock(&pool->mutex);
+
+ ngx_slab_free_locked(pool, p);
+
+ ngx_shmtx_unlock(&pool->mutex);
+}
+
+
+void
+ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
+{
+ size_t size;
+ uintptr_t slab, m, *bitmap;
+ ngx_uint_t i, n, type, slot, shift, map;
+ ngx_slab_page_t *slots, *page;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
+
+ if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
+ ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool");
+ goto fail;
+ }
+
+ n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
+ page = &pool->pages[n];
+ slab = page->slab;
+ type = ngx_slab_page_type(page);
+
+ switch (type) {
+
+ case NGX_SLAB_SMALL:
+
+ shift = slab & NGX_SLAB_SHIFT_MASK;
+ size = (size_t) 1 << shift;
+
+ if ((uintptr_t) p & (size - 1)) {
+ goto wrong_chunk;
+ }
+
+ n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift;
+ m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8));
+ n /= sizeof(uintptr_t) * 8;
+ bitmap = (uintptr_t *)
+ ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1));
+
+ if (bitmap[n] & m) {
+ slot = shift - pool->min_shift;
+
+ if (page->next == NULL) {
+ slots = ngx_slab_slots(pool);
+
+ page->next = slots[slot].next;
+ slots[slot].next = page;
+
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_SMALL;
+ page->next->prev = (uintptr_t) page | NGX_SLAB_SMALL;
+ }
+
+ bitmap[n] &= ~m;
+
+ n = (ngx_pagesize >> shift) / ((1 << shift) * 8);
+
+ if (n == 0) {
+ n = 1;
+ }
+
+ if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) {
+ goto done;
+ }
+
+ map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8);
+
+ for (i = 1; i < map; i++) {
+ if (bitmap[i]) {
+ goto done;
+ }
+ }
+
+ ngx_slab_free_pages(pool, page, 1);
+
+ pool->stats[slot].total -= (ngx_pagesize >> shift) - n;
+
+ goto done;
+ }
+
+ goto chunk_already_free;
+
+ case NGX_SLAB_EXACT:
+
+ m = (uintptr_t) 1 <<
+ (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift);
+ size = ngx_slab_exact_size;
+
+ if ((uintptr_t) p & (size - 1)) {
+ goto wrong_chunk;
+ }
+
+ if (slab & m) {
+ slot = ngx_slab_exact_shift - pool->min_shift;
+
+ if (slab == NGX_SLAB_BUSY) {
+ slots = ngx_slab_slots(pool);
+
+ page->next = slots[slot].next;
+ slots[slot].next = page;
+
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_EXACT;
+ page->next->prev = (uintptr_t) page | NGX_SLAB_EXACT;
+ }
+
+ page->slab &= ~m;
+
+ if (page->slab) {
+ goto done;
+ }
+
+ ngx_slab_free_pages(pool, page, 1);
+
+ pool->stats[slot].total -= sizeof(uintptr_t) * 8;
+
+ goto done;
+ }
+
+ goto chunk_already_free;
+
+ case NGX_SLAB_BIG:
+
+ shift = slab & NGX_SLAB_SHIFT_MASK;
+ size = (size_t) 1 << shift;
+
+ if ((uintptr_t) p & (size - 1)) {
+ goto wrong_chunk;
+ }
+
+ m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift)
+ + NGX_SLAB_MAP_SHIFT);
+
+ if (slab & m) {
+ slot = shift - pool->min_shift;
+
+ if (page->next == NULL) {
+ slots = ngx_slab_slots(pool);
+
+ page->next = slots[slot].next;
+ slots[slot].next = page;
+
+ page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG;
+ page->next->prev = (uintptr_t) page | NGX_SLAB_BIG;
+ }
+
+ page->slab &= ~m;
+
+ if (page->slab & NGX_SLAB_MAP_MASK) {
+ goto done;
+ }
+
+ ngx_slab_free_pages(pool, page, 1);
+
+ pool->stats[slot].total -= ngx_pagesize >> shift;
+
+ goto done;
+ }
+
+ goto chunk_already_free;
+
+ case NGX_SLAB_PAGE:
+
+ if ((uintptr_t) p & (ngx_pagesize - 1)) {
+ goto wrong_chunk;
+ }
+
+ if (!(slab & NGX_SLAB_PAGE_START)) {
+ ngx_slab_error(pool, NGX_LOG_ALERT,
+ "ngx_slab_free(): page is already free");
+ goto fail;
+ }
+
+ if (slab == NGX_SLAB_PAGE_BUSY) {
+ ngx_slab_error(pool, NGX_LOG_ALERT,
+ "ngx_slab_free(): pointer to wrong page");
+ goto fail;
+ }
+
+ n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
+ size = slab & ~NGX_SLAB_PAGE_START;
+
+ ngx_slab_free_pages(pool, &pool->pages[n], size);
+
+ ngx_slab_junk(p, size << ngx_pagesize_shift);
+
+ return;
+ }
+
+ /* not reached */
+
+ return;
+
+done:
+
+ pool->stats[slot].used--;
+
+ ngx_slab_junk(p, size);
+
+ return;
+
+wrong_chunk:
+
+ ngx_slab_error(pool, NGX_LOG_ALERT,
+ "ngx_slab_free(): pointer to wrong chunk");
+
+ goto fail;
+
+chunk_already_free:
+
+ ngx_slab_error(pool, NGX_LOG_ALERT,
+ "ngx_slab_free(): chunk is already free");
+
+fail:
+
+ return;
+}
+
+
+static ngx_slab_page_t *
+ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
+{
+ ngx_slab_page_t *page, *p;
+
+ for (page = pool->free.next; page != &pool->free; page = page->next) {
+
+ if (page->slab >= pages) {
+
+ if (page->slab > pages) {
+ page[page->slab - 1].prev = (uintptr_t) &page[pages];
+
+ page[pages].slab = page->slab - pages;
+ page[pages].next = page->next;
+ page[pages].prev = page->prev;
+
+ p = (ngx_slab_page_t *) page->prev;
+ p->next = &page[pages];
+ page->next->prev = (uintptr_t) &page[pages];
+
+ } else {
+ p = (ngx_slab_page_t *) page->prev;
+ p->next = page->next;
+ page->next->prev = page->prev;
+ }
+
+ page->slab = pages | NGX_SLAB_PAGE_START;
+ page->next = NULL;
+ page->prev = NGX_SLAB_PAGE;
+
+ pool->pfree -= pages;
+
+ if (--pages == 0) {
+ return page;
+ }
+
+ for (p = page + 1; pages; pages--) {
+ p->slab = NGX_SLAB_PAGE_BUSY;
+ p->next = NULL;
+ p->prev = NGX_SLAB_PAGE;
+ p++;
+ }
+
+ return page;
+ }
+ }
+
+ if (pool->log_nomem) {
+ ngx_slab_error(pool, NGX_LOG_CRIT,
+ "ngx_slab_alloc() failed: no memory");
+ }
+
+ return NULL;
+}
+
+
+static void
+ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
+ ngx_uint_t pages)
+{
+ ngx_slab_page_t *prev, *join;
+
+ pool->pfree += pages;
+
+ page->slab = pages--;
+
+ if (pages) {
+ ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
+ }
+
+ if (page->next) {
+ prev = ngx_slab_page_prev(page);
+ prev->next = page->next;
+ page->next->prev = page->prev;
+ }
+
+ join = page + page->slab;
+
+ if (join < pool->last) {
+
+ if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
+
+ if (join->next != NULL) {
+ pages += join->slab;
+ page->slab += join->slab;
+
+ prev = ngx_slab_page_prev(join);
+ prev->next = join->next;
+ join->next->prev = join->prev;
+
+ join->slab = NGX_SLAB_PAGE_FREE;
+ join->next = NULL;
+ join->prev = NGX_SLAB_PAGE;
+ }
+ }
+ }
+
+ if (page > pool->pages) {
+ join = page - 1;
+
+ if (ngx_slab_page_type(join) == NGX_SLAB_PAGE) {
+
+ if (join->slab == NGX_SLAB_PAGE_FREE) {
+ join = ngx_slab_page_prev(join);
+ }
+
+ if (join->next != NULL) {
+ pages += join->slab;
+ join->slab += page->slab;
+
+ prev = ngx_slab_page_prev(join);
+ prev->next = join->next;
+ join->next->prev = join->prev;
+
+ page->slab = NGX_SLAB_PAGE_FREE;
+ page->next = NULL;
+ page->prev = NGX_SLAB_PAGE;
+
+ page = join;
+ }
+ }
+ }
+
+ if (pages) {
+ page[pages].prev = (uintptr_t) page;
+ }
+
+ page->prev = (uintptr_t) &pool->free;
+ page->next = pool->free.next;
+
+ page->next->prev = (uintptr_t) page;
+
+ pool->free.next = page;
+}
+
+
+static void
+ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text)
+{
+ ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx);
+}
diff --git a/app/nginx/src/core/ngx_slab.h b/app/nginx/src/core/ngx_slab.h
new file mode 100644
index 0000000..eff893c
--- /dev/null
+++ b/app/nginx/src/core/ngx_slab.h
@@ -0,0 +1,71 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SLAB_H_INCLUDED_
+#define _NGX_SLAB_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct ngx_slab_page_s ngx_slab_page_t;
+
+struct ngx_slab_page_s {
+ uintptr_t slab;
+ ngx_slab_page_t *next;
+ uintptr_t prev;
+};
+
+
+typedef struct {
+ ngx_uint_t total;
+ ngx_uint_t used;
+
+ ngx_uint_t reqs;
+ ngx_uint_t fails;
+} ngx_slab_stat_t;
+
+
+typedef struct {
+ ngx_shmtx_sh_t lock;
+
+ size_t min_size;
+ size_t min_shift;
+
+ ngx_slab_page_t *pages;
+ ngx_slab_page_t *last;
+ ngx_slab_page_t free;
+
+ ngx_slab_stat_t *stats;
+ ngx_uint_t pfree;
+
+ u_char *start;
+ u_char *end;
+
+ ngx_shmtx_t mutex;
+
+ u_char *log_ctx;
+ u_char zero;
+
+ unsigned log_nomem:1;
+
+ void *data;
+ void *addr;
+} ngx_slab_pool_t;
+
+
+void ngx_slab_init(ngx_slab_pool_t *pool);
+void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
+void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
+void *ngx_slab_calloc(ngx_slab_pool_t *pool, size_t size);
+void *ngx_slab_calloc_locked(ngx_slab_pool_t *pool, size_t size);
+void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
+void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
+
+
+#endif /* _NGX_SLAB_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_spinlock.c b/app/nginx/src/core/ngx_spinlock.c
new file mode 100644
index 0000000..9c93afa
--- /dev/null
+++ b/app/nginx/src/core/ngx_spinlock.c
@@ -0,0 +1,53 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+void
+ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin)
+{
+
+#if (NGX_HAVE_ATOMIC_OPS)
+
+ ngx_uint_t i, n;
+
+ for ( ;; ) {
+
+ if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
+ return;
+ }
+
+ if (ngx_ncpu > 1) {
+
+ for (n = 1; n < spin; n <<= 1) {
+
+ for (i = 0; i < n; i++) {
+ ngx_cpu_pause();
+ }
+
+ if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) {
+ return;
+ }
+ }
+ }
+
+ ngx_sched_yield();
+ }
+
+#else
+
+#if (NGX_THREADS)
+
+#error ngx_spinlock() or ngx_atomic_cmp_set() are not defined !
+
+#endif
+
+#endif
+
+}
diff --git a/app/nginx/src/core/ngx_string.c b/app/nginx/src/core/ngx_string.c
new file mode 100644
index 0000000..7a73ef5
--- /dev/null
+++ b/app/nginx/src/core/ngx_string.c
@@ -0,0 +1,1976 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
+ u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
+static void ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
+ const u_char *basis, ngx_uint_t padding);
+static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
+ const u_char *basis);
+
+
+void
+ngx_strlow(u_char *dst, u_char *src, size_t n)
+{
+ while (n) {
+ *dst = ngx_tolower(*src);
+ dst++;
+ src++;
+ n--;
+ }
+}
+
+
+u_char *
+ngx_cpystrn(u_char *dst, u_char *src, size_t n)
+{
+ if (n == 0) {
+ return dst;
+ }
+
+ while (--n) {
+ *dst = *src;
+
+ if (*dst == '\0') {
+ return dst;
+ }
+
+ dst++;
+ src++;
+ }
+
+ *dst = '\0';
+
+ return dst;
+}
+
+
+u_char *
+ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
+{
+ u_char *dst;
+
+ dst = ngx_pnalloc(pool, src->len);
+ if (dst == NULL) {
+ return NULL;
+ }
+
+ ngx_memcpy(dst, src->data, src->len);
+
+ return dst;
+}
+
+
+/*
+ * supported formats:
+ * %[0][width][x][X]O off_t
+ * %[0][width]T time_t
+ * %[0][width][u][x|X]z ssize_t/size_t
+ * %[0][width][u][x|X]d int/u_int
+ * %[0][width][u][x|X]l long
+ * %[0][width|m][u][x|X]i ngx_int_t/ngx_uint_t
+ * %[0][width][u][x|X]D int32_t/uint32_t
+ * %[0][width][u][x|X]L int64_t/uint64_t
+ * %[0][width|m][u][x|X]A ngx_atomic_int_t/ngx_atomic_uint_t
+ * %[0][width][.width]f double, max valid number fits to %18.15f
+ * %P ngx_pid_t
+ * %M ngx_msec_t
+ * %r rlim_t
+ * %p void *
+ * %V ngx_str_t *
+ * %v ngx_variable_value_t *
+ * %s null-terminated string
+ * %*s length and string
+ * %Z '\0'
+ * %N '\n'
+ * %c char
+ * %% %
+ *
+ * reserved:
+ * %t ptrdiff_t
+ * %S null-terminated wchar string
+ * %C wchar
+ */
+
+
+u_char * ngx_cdecl
+ngx_sprintf(u_char *buf, const char *fmt, ...)
+{
+ u_char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(buf, (void *) -1, fmt, args);
+ va_end(args);
+
+ return p;
+}
+
+
+u_char * ngx_cdecl
+ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...)
+{
+ u_char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(buf, buf + max, fmt, args);
+ va_end(args);
+
+ return p;
+}
+
+
+u_char * ngx_cdecl
+ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...)
+{
+ u_char *p;
+ va_list args;
+
+ va_start(args, fmt);
+ p = ngx_vslprintf(buf, last, fmt, args);
+ va_end(args);
+
+ return p;
+}
+
+
+u_char *
+ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args)
+{
+ u_char *p, zero;
+ int d;
+ double f;
+ size_t len, slen;
+ int64_t i64;
+ uint64_t ui64, frac;
+ ngx_msec_t ms;
+ ngx_uint_t width, sign, hex, max_width, frac_width, scale, n;
+ ngx_str_t *v;
+ ngx_variable_value_t *vv;
+
+ while (*fmt && buf < last) {
+
+ /*
+ * "buf < last" means that we could copy at least one character:
+ * the plain character, "%%", "%c", and minus without the checking
+ */
+
+ if (*fmt == '%') {
+
+ i64 = 0;
+ ui64 = 0;
+
+ zero = (u_char) ((*++fmt == '0') ? '0' : ' ');
+ width = 0;
+ sign = 1;
+ hex = 0;
+ max_width = 0;
+ frac_width = 0;
+ slen = (size_t) -1;
+
+ while (*fmt >= '0' && *fmt <= '9') {
+ width = width * 10 + *fmt++ - '0';
+ }
+
+
+ for ( ;; ) {
+ switch (*fmt) {
+
+ case 'u':
+ sign = 0;
+ fmt++;
+ continue;
+
+ case 'm':
+ max_width = 1;
+ fmt++;
+ continue;
+
+ case 'X':
+ hex = 2;
+ sign = 0;
+ fmt++;
+ continue;
+
+ case 'x':
+ hex = 1;
+ sign = 0;
+ fmt++;
+ continue;
+
+ case '.':
+ fmt++;
+
+ while (*fmt >= '0' && *fmt <= '9') {
+ frac_width = frac_width * 10 + *fmt++ - '0';
+ }
+
+ break;
+
+ case '*':
+ slen = va_arg(args, size_t);
+ fmt++;
+ continue;
+
+ default:
+ break;
+ }
+
+ break;
+ }
+
+
+ switch (*fmt) {
+
+ case 'V':
+ v = va_arg(args, ngx_str_t *);
+
+ len = ngx_min(((size_t) (last - buf)), v->len);
+ buf = ngx_cpymem(buf, v->data, len);
+ fmt++;
+
+ continue;
+
+ case 'v':
+ vv = va_arg(args, ngx_variable_value_t *);
+
+ len = ngx_min(((size_t) (last - buf)), vv->len);
+ buf = ngx_cpymem(buf, vv->data, len);
+ fmt++;
+
+ continue;
+
+ case 's':
+ p = va_arg(args, u_char *);
+
+ if (slen == (size_t) -1) {
+ while (*p && buf < last) {
+ *buf++ = *p++;
+ }
+
+ } else {
+ len = ngx_min(((size_t) (last - buf)), slen);
+ buf = ngx_cpymem(buf, p, len);
+ }
+
+ fmt++;
+
+ continue;
+
+ case 'O':
+ i64 = (int64_t) va_arg(args, off_t);
+ sign = 1;
+ break;
+
+ case 'P':
+ i64 = (int64_t) va_arg(args, ngx_pid_t);
+ sign = 1;
+ break;
+
+ case 'T':
+ i64 = (int64_t) va_arg(args, time_t);
+ sign = 1;
+ break;
+
+ case 'M':
+ ms = (ngx_msec_t) va_arg(args, ngx_msec_t);
+ if ((ngx_msec_int_t) ms == -1) {
+ sign = 1;
+ i64 = -1;
+ } else {
+ sign = 0;
+ ui64 = (uint64_t) ms;
+ }
+ break;
+
+ case 'z':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, ssize_t);
+ } else {
+ ui64 = (uint64_t) va_arg(args, size_t);
+ }
+ break;
+
+ case 'i':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, ngx_int_t);
+ } else {
+ ui64 = (uint64_t) va_arg(args, ngx_uint_t);
+ }
+
+ if (max_width) {
+ width = NGX_INT_T_LEN;
+ }
+
+ break;
+
+ case 'd':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, int);
+ } else {
+ ui64 = (uint64_t) va_arg(args, u_int);
+ }
+ break;
+
+ case 'l':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, long);
+ } else {
+ ui64 = (uint64_t) va_arg(args, u_long);
+ }
+ break;
+
+ case 'D':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, int32_t);
+ } else {
+ ui64 = (uint64_t) va_arg(args, uint32_t);
+ }
+ break;
+
+ case 'L':
+ if (sign) {
+ i64 = va_arg(args, int64_t);
+ } else {
+ ui64 = va_arg(args, uint64_t);
+ }
+ break;
+
+ case 'A':
+ if (sign) {
+ i64 = (int64_t) va_arg(args, ngx_atomic_int_t);
+ } else {
+ ui64 = (uint64_t) va_arg(args, ngx_atomic_uint_t);
+ }
+
+ if (max_width) {
+ width = NGX_ATOMIC_T_LEN;
+ }
+
+ break;
+
+ case 'f':
+ f = va_arg(args, double);
+
+ if (f < 0) {
+ *buf++ = '-';
+ f = -f;
+ }
+
+ ui64 = (int64_t) f;
+ frac = 0;
+
+ if (frac_width) {
+
+ scale = 1;
+ for (n = frac_width; n; n--) {
+ scale *= 10;
+ }
+
+ frac = (uint64_t) ((f - (double) ui64) * scale + 0.5);
+
+ if (frac == scale) {
+ ui64++;
+ frac = 0;
+ }
+ }
+
+ buf = ngx_sprintf_num(buf, last, ui64, zero, 0, width);
+
+ if (frac_width) {
+ if (buf < last) {
+ *buf++ = '.';
+ }
+
+ buf = ngx_sprintf_num(buf, last, frac, '0', 0, frac_width);
+ }
+
+ fmt++;
+
+ continue;
+
+#if !(NGX_WIN32)
+ case 'r':
+ i64 = (int64_t) va_arg(args, rlim_t);
+ sign = 1;
+ break;
+#endif
+
+ case 'p':
+ ui64 = (uintptr_t) va_arg(args, void *);
+ hex = 2;
+ sign = 0;
+ zero = '0';
+ width = 2 * sizeof(void *);
+ break;
+
+ case 'c':
+ d = va_arg(args, int);
+ *buf++ = (u_char) (d & 0xff);
+ fmt++;
+
+ continue;
+
+ case 'Z':
+ *buf++ = '\0';
+ fmt++;
+
+ continue;
+
+ case 'N':
+#if (NGX_WIN32)
+ *buf++ = CR;
+ if (buf < last) {
+ *buf++ = LF;
+ }
+#else
+ *buf++ = LF;
+#endif
+ fmt++;
+
+ continue;
+
+ case '%':
+ *buf++ = '%';
+ fmt++;
+
+ continue;
+
+ default:
+ *buf++ = *fmt++;
+
+ continue;
+ }
+
+ if (sign) {
+ if (i64 < 0) {
+ *buf++ = '-';
+ ui64 = (uint64_t) -i64;
+
+ } else {
+ ui64 = (uint64_t) i64;
+ }
+ }
+
+ buf = ngx_sprintf_num(buf, last, ui64, zero, hex, width);
+
+ fmt++;
+
+ } else {
+ *buf++ = *fmt++;
+ }
+ }
+
+ return buf;
+}
+
+
+static u_char *
+ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64, u_char zero,
+ ngx_uint_t hexadecimal, ngx_uint_t width)
+{
+ u_char *p, temp[NGX_INT64_LEN + 1];
+ /*
+ * we need temp[NGX_INT64_LEN] only,
+ * but icc issues the warning
+ */
+ size_t len;
+ uint32_t ui32;
+ static u_char hex[] = "0123456789abcdef";
+ static u_char HEX[] = "0123456789ABCDEF";
+
+ p = temp + NGX_INT64_LEN;
+
+ if (hexadecimal == 0) {
+
+ if (ui64 <= (uint64_t) NGX_MAX_UINT32_VALUE) {
+
+ /*
+ * To divide 64-bit numbers and to find remainders
+ * on the x86 platform gcc and icc call the libc functions
+ * [u]divdi3() and [u]moddi3(), they call another function
+ * in its turn. On FreeBSD it is the qdivrem() function,
+ * its source code is about 170 lines of the code.
+ * The glibc counterpart is about 150 lines of the code.
+ *
+ * For 32-bit numbers and some divisors gcc and icc use
+ * a inlined multiplication and shifts. For example,
+ * unsigned "i32 / 10" is compiled to
+ *
+ * (i32 * 0xCCCCCCCD) >> 35
+ */
+
+ ui32 = (uint32_t) ui64;
+
+ do {
+ *--p = (u_char) (ui32 % 10 + '0');
+ } while (ui32 /= 10);
+
+ } else {
+ do {
+ *--p = (u_char) (ui64 % 10 + '0');
+ } while (ui64 /= 10);
+ }
+
+ } else if (hexadecimal == 1) {
+
+ do {
+
+ /* the "(uint32_t)" cast disables the BCC's warning */
+ *--p = hex[(uint32_t) (ui64 & 0xf)];
+
+ } while (ui64 >>= 4);
+
+ } else { /* hexadecimal == 2 */
+
+ do {
+
+ /* the "(uint32_t)" cast disables the BCC's warning */
+ *--p = HEX[(uint32_t) (ui64 & 0xf)];
+
+ } while (ui64 >>= 4);
+ }
+
+ /* zero or space padding */
+
+ len = (temp + NGX_INT64_LEN) - p;
+
+ while (len++ < width && buf < last) {
+ *buf++ = zero;
+ }
+
+ /* number safe copy */
+
+ len = (temp + NGX_INT64_LEN) - p;
+
+ if (buf + len > last) {
+ len = last - buf;
+ }
+
+ return ngx_cpymem(buf, p, len);
+}
+
+
+/*
+ * We use ngx_strcasecmp()/ngx_strncasecmp() for 7-bit ASCII strings only,
+ * and implement our own ngx_strcasecmp()/ngx_strncasecmp()
+ * to avoid libc locale overhead. Besides, we use the ngx_uint_t's
+ * instead of the u_char's, because they are slightly faster.
+ */
+
+ngx_int_t
+ngx_strcasecmp(u_char *s1, u_char *s2)
+{
+ ngx_uint_t c1, c2;
+
+ for ( ;; ) {
+ c1 = (ngx_uint_t) *s1++;
+ c2 = (ngx_uint_t) *s2++;
+
+ c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+ c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+ if (c1 == c2) {
+
+ if (c1) {
+ continue;
+ }
+
+ return 0;
+ }
+
+ return c1 - c2;
+ }
+}
+
+
+ngx_int_t
+ngx_strncasecmp(u_char *s1, u_char *s2, size_t n)
+{
+ ngx_uint_t c1, c2;
+
+ while (n) {
+ c1 = (ngx_uint_t) *s1++;
+ c2 = (ngx_uint_t) *s2++;
+
+ c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+ c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+ if (c1 == c2) {
+
+ if (c1) {
+ n--;
+ continue;
+ }
+
+ return 0;
+ }
+
+ return c1 - c2;
+ }
+
+ return 0;
+}
+
+
+u_char *
+ngx_strnstr(u_char *s1, char *s2, size_t len)
+{
+ u_char c1, c2;
+ size_t n;
+
+ c2 = *(u_char *) s2++;
+
+ n = ngx_strlen(s2);
+
+ do {
+ do {
+ if (len-- == 0) {
+ return NULL;
+ }
+
+ c1 = *s1++;
+
+ if (c1 == 0) {
+ return NULL;
+ }
+
+ } while (c1 != c2);
+
+ if (n > len) {
+ return NULL;
+ }
+
+ } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
+
+ return --s1;
+}
+
+
+/*
+ * ngx_strstrn() and ngx_strcasestrn() are intended to search for static
+ * substring with known length in null-terminated string. The argument n
+ * must be length of the second substring - 1.
+ */
+
+u_char *
+ngx_strstrn(u_char *s1, char *s2, size_t n)
+{
+ u_char c1, c2;
+
+ c2 = *(u_char *) s2++;
+
+ do {
+ do {
+ c1 = *s1++;
+
+ if (c1 == 0) {
+ return NULL;
+ }
+
+ } while (c1 != c2);
+
+ } while (ngx_strncmp(s1, (u_char *) s2, n) != 0);
+
+ return --s1;
+}
+
+
+u_char *
+ngx_strcasestrn(u_char *s1, char *s2, size_t n)
+{
+ ngx_uint_t c1, c2;
+
+ c2 = (ngx_uint_t) *s2++;
+ c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+ do {
+ do {
+ c1 = (ngx_uint_t) *s1++;
+
+ if (c1 == 0) {
+ return NULL;
+ }
+
+ c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+
+ } while (c1 != c2);
+
+ } while (ngx_strncasecmp(s1, (u_char *) s2, n) != 0);
+
+ return --s1;
+}
+
+
+/*
+ * ngx_strlcasestrn() is intended to search for static substring
+ * with known length in string until the argument last. The argument n
+ * must be length of the second substring - 1.
+ */
+
+u_char *
+ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n)
+{
+ ngx_uint_t c1, c2;
+
+ c2 = (ngx_uint_t) *s2++;
+ c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+ last -= n;
+
+ do {
+ do {
+ if (s1 >= last) {
+ return NULL;
+ }
+
+ c1 = (ngx_uint_t) *s1++;
+
+ c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+
+ } while (c1 != c2);
+
+ } while (ngx_strncasecmp(s1, s2, n) != 0);
+
+ return --s1;
+}
+
+
+ngx_int_t
+ngx_rstrncmp(u_char *s1, u_char *s2, size_t n)
+{
+ if (n == 0) {
+ return 0;
+ }
+
+ n--;
+
+ for ( ;; ) {
+ if (s1[n] != s2[n]) {
+ return s1[n] - s2[n];
+ }
+
+ if (n == 0) {
+ return 0;
+ }
+
+ n--;
+ }
+}
+
+
+ngx_int_t
+ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n)
+{
+ u_char c1, c2;
+
+ if (n == 0) {
+ return 0;
+ }
+
+ n--;
+
+ for ( ;; ) {
+ c1 = s1[n];
+ if (c1 >= 'a' && c1 <= 'z') {
+ c1 -= 'a' - 'A';
+ }
+
+ c2 = s2[n];
+ if (c2 >= 'a' && c2 <= 'z') {
+ c2 -= 'a' - 'A';
+ }
+
+ if (c1 != c2) {
+ return c1 - c2;
+ }
+
+ if (n == 0) {
+ return 0;
+ }
+
+ n--;
+ }
+}
+
+
+ngx_int_t
+ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2)
+{
+ size_t n;
+ ngx_int_t m, z;
+
+ if (n1 <= n2) {
+ n = n1;
+ z = -1;
+
+ } else {
+ n = n2;
+ z = 1;
+ }
+
+ m = ngx_memcmp(s1, s2, n);
+
+ if (m || n1 == n2) {
+ return m;
+ }
+
+ return z;
+}
+
+
+ngx_int_t
+ngx_dns_strcmp(u_char *s1, u_char *s2)
+{
+ ngx_uint_t c1, c2;
+
+ for ( ;; ) {
+ c1 = (ngx_uint_t) *s1++;
+ c2 = (ngx_uint_t) *s2++;
+
+ c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1;
+ c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2;
+
+ if (c1 == c2) {
+
+ if (c1) {
+ continue;
+ }
+
+ return 0;
+ }
+
+ /* in ASCII '.' > '-', but we need '.' to be the lowest character */
+
+ c1 = (c1 == '.') ? ' ' : c1;
+ c2 = (c2 == '.') ? ' ' : c2;
+
+ return c1 - c2;
+ }
+}
+
+
+ngx_int_t
+ngx_filename_cmp(u_char *s1, u_char *s2, size_t n)
+{
+ ngx_uint_t c1, c2;
+
+ while (n) {
+ c1 = (ngx_uint_t) *s1++;
+ c2 = (ngx_uint_t) *s2++;
+
+#if (NGX_HAVE_CASELESS_FILESYSTEM)
+ c1 = tolower(c1);
+ c2 = tolower(c2);
+#endif
+
+ if (c1 == c2) {
+
+ if (c1) {
+ n--;
+ continue;
+ }
+
+ return 0;
+ }
+
+ /* we need '/' to be the lowest character */
+
+ if (c1 == 0 || c2 == 0) {
+ return c1 - c2;
+ }
+
+ c1 = (c1 == '/') ? 0 : c1;
+ c2 = (c2 == '/') ? 0 : c2;
+
+ return c1 - c2;
+ }
+
+ return 0;
+}
+
+
+ngx_int_t
+ngx_atoi(u_char *line, size_t n)
+{
+ ngx_int_t value, cutoff, cutlim;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
+
+ for (value = 0; n--; line++) {
+ if (*line < '0' || *line > '9') {
+ return NGX_ERROR;
+ }
+
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*line - '0');
+ }
+
+ return value;
+}
+
+
+/* parse a fixed point number, e.g., ngx_atofp("10.5", 4, 2) returns 1050 */
+
+ngx_int_t
+ngx_atofp(u_char *line, size_t n, size_t point)
+{
+ ngx_int_t value, cutoff, cutlim;
+ ngx_uint_t dot;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_INT_T_VALUE / 10;
+ cutlim = NGX_MAX_INT_T_VALUE % 10;
+
+ dot = 0;
+
+ for (value = 0; n--; line++) {
+
+ if (point == 0) {
+ return NGX_ERROR;
+ }
+
+ if (*line == '.') {
+ if (dot) {
+ return NGX_ERROR;
+ }
+
+ dot = 1;
+ continue;
+ }
+
+ if (*line < '0' || *line > '9') {
+ return NGX_ERROR;
+ }
+
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*line - '0');
+ point -= dot;
+ }
+
+ while (point--) {
+ if (value > cutoff) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10;
+ }
+
+ return value;
+}
+
+
+ssize_t
+ngx_atosz(u_char *line, size_t n)
+{
+ ssize_t value, cutoff, cutlim;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_SIZE_T_VALUE / 10;
+ cutlim = NGX_MAX_SIZE_T_VALUE % 10;
+
+ for (value = 0; n--; line++) {
+ if (*line < '0' || *line > '9') {
+ return NGX_ERROR;
+ }
+
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*line - '0');
+ }
+
+ return value;
+}
+
+
+off_t
+ngx_atoof(u_char *line, size_t n)
+{
+ off_t value, cutoff, cutlim;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_OFF_T_VALUE / 10;
+ cutlim = NGX_MAX_OFF_T_VALUE % 10;
+
+ for (value = 0; n--; line++) {
+ if (*line < '0' || *line > '9') {
+ return NGX_ERROR;
+ }
+
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*line - '0');
+ }
+
+ return value;
+}
+
+
+time_t
+ngx_atotm(u_char *line, size_t n)
+{
+ time_t value, cutoff, cutlim;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_TIME_T_VALUE / 10;
+ cutlim = NGX_MAX_TIME_T_VALUE % 10;
+
+ for (value = 0; n--; line++) {
+ if (*line < '0' || *line > '9') {
+ return NGX_ERROR;
+ }
+
+ if (value >= cutoff && (value > cutoff || *line - '0' > cutlim)) {
+ return NGX_ERROR;
+ }
+
+ value = value * 10 + (*line - '0');
+ }
+
+ return value;
+}
+
+
+ngx_int_t
+ngx_hextoi(u_char *line, size_t n)
+{
+ u_char c, ch;
+ ngx_int_t value, cutoff;
+
+ if (n == 0) {
+ return NGX_ERROR;
+ }
+
+ cutoff = NGX_MAX_INT_T_VALUE / 16;
+
+ for (value = 0; n--; line++) {
+ if (value > cutoff) {
+ return NGX_ERROR;
+ }
+
+ ch = *line;
+
+ if (ch >= '0' && ch <= '9') {
+ value = value * 16 + (ch - '0');
+ continue;
+ }
+
+ c = (u_char) (ch | 0x20);
+
+ if (c >= 'a' && c <= 'f') {
+ value = value * 16 + (c - 'a' + 10);
+ continue;
+ }
+
+ return NGX_ERROR;
+ }
+
+ return value;
+}
+
+
+u_char *
+ngx_hex_dump(u_char *dst, u_char *src, size_t len)
+{
+ static u_char hex[] = "0123456789abcdef";
+
+ while (len--) {
+ *dst++ = hex[*src >> 4];
+ *dst++ = hex[*src++ & 0xf];
+ }
+
+ return dst;
+}
+
+
+void
+ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
+{
+ static u_char basis64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ ngx_encode_base64_internal(dst, src, basis64, 1);
+}
+
+
+void
+ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src)
+{
+ static u_char basis64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ ngx_encode_base64_internal(dst, src, basis64, 0);
+}
+
+
+static void
+ngx_encode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis,
+ ngx_uint_t padding)
+{
+ u_char *d, *s;
+ size_t len;
+
+ len = src->len;
+ s = src->data;
+ d = dst->data;
+
+ while (len > 2) {
+ *d++ = basis[(s[0] >> 2) & 0x3f];
+ *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
+ *d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
+ *d++ = basis[s[2] & 0x3f];
+
+ s += 3;
+ len -= 3;
+ }
+
+ if (len) {
+ *d++ = basis[(s[0] >> 2) & 0x3f];
+
+ if (len == 1) {
+ *d++ = basis[(s[0] & 3) << 4];
+ if (padding) {
+ *d++ = '=';
+ }
+
+ } else {
+ *d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
+ *d++ = basis[(s[1] & 0x0f) << 2];
+ }
+
+ if (padding) {
+ *d++ = '=';
+ }
+ }
+
+ dst->len = d - dst->data;
+}
+
+
+ngx_int_t
+ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
+{
+ static u_char basis64[] = {
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
+ 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
+ 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
+
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
+ };
+
+ return ngx_decode_base64_internal(dst, src, basis64);
+}
+
+
+ngx_int_t
+ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
+{
+ static u_char basis64[] = {
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
+ 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
+ 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
+
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
+ };
+
+ return ngx_decode_base64_internal(dst, src, basis64);
+}
+
+
+static ngx_int_t
+ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
+{
+ size_t len;
+ u_char *d, *s;
+
+ for (len = 0; len < src->len; len++) {
+ if (src->data[len] == '=') {
+ break;
+ }
+
+ if (basis[src->data[len]] == 77) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (len % 4 == 1) {
+ return NGX_ERROR;
+ }
+
+ s = src->data;
+ d = dst->data;
+
+ while (len > 3) {
+ *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
+ *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
+ *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
+
+ s += 4;
+ len -= 4;
+ }
+
+ if (len > 1) {
+ *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
+ }
+
+ if (len > 2) {
+ *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
+ }
+
+ dst->len = d - dst->data;
+
+ return NGX_OK;
+}
+
+
+/*
+ * ngx_utf8_decode() decodes two and more bytes UTF sequences only
+ * the return values:
+ * 0x80 - 0x10ffff valid character
+ * 0x110000 - 0xfffffffd invalid sequence
+ * 0xfffffffe incomplete sequence
+ * 0xffffffff error
+ */
+
+uint32_t
+ngx_utf8_decode(u_char **p, size_t n)
+{
+ size_t len;
+ uint32_t u, i, valid;
+
+ u = **p;
+
+ if (u >= 0xf0) {
+
+ u &= 0x07;
+ valid = 0xffff;
+ len = 3;
+
+ } else if (u >= 0xe0) {
+
+ u &= 0x0f;
+ valid = 0x7ff;
+ len = 2;
+
+ } else if (u >= 0xc2) {
+
+ u &= 0x1f;
+ valid = 0x7f;
+ len = 1;
+
+ } else {
+ (*p)++;
+ return 0xffffffff;
+ }
+
+ if (n - 1 < len) {
+ return 0xfffffffe;
+ }
+
+ (*p)++;
+
+ while (len) {
+ i = *(*p)++;
+
+ if (i < 0x80) {
+ return 0xffffffff;
+ }
+
+ u = (u << 6) | (i & 0x3f);
+
+ len--;
+ }
+
+ if (u > valid) {
+ return u;
+ }
+
+ return 0xffffffff;
+}
+
+
+size_t
+ngx_utf8_length(u_char *p, size_t n)
+{
+ u_char c, *last;
+ size_t len;
+
+ last = p + n;
+
+ for (len = 0; p < last; len++) {
+
+ c = *p;
+
+ if (c < 0x80) {
+ p++;
+ continue;
+ }
+
+ if (ngx_utf8_decode(&p, n) > 0x10ffff) {
+ /* invalid UTF-8 */
+ return n;
+ }
+ }
+
+ return len;
+}
+
+
+u_char *
+ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len)
+{
+ u_char c, *next;
+
+ if (n == 0) {
+ return dst;
+ }
+
+ while (--n) {
+
+ c = *src;
+ *dst = c;
+
+ if (c < 0x80) {
+
+ if (c != '\0') {
+ dst++;
+ src++;
+ len--;
+
+ continue;
+ }
+
+ return dst;
+ }
+
+ next = src;
+
+ if (ngx_utf8_decode(&next, len) > 0x10ffff) {
+ /* invalid UTF-8 */
+ break;
+ }
+
+ while (src < next) {
+ *dst++ = *src++;
+ len--;
+ }
+ }
+
+ *dst = '\0';
+
+ return dst;
+}
+
+
+uintptr_t
+ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type)
+{
+ ngx_uint_t n;
+ uint32_t *escape;
+ static u_char hex[] = "0123456789ABCDEF";
+
+ /* " ", "#", "%", "?", %00-%1F, %7F-%FF */
+
+ static uint32_t uri[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ };
+
+ /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */
+
+ static uint32_t args[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ };
+
+ /* not ALPHA, DIGIT, "-", ".", "_", "~" */
+
+ static uint32_t uri_component[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */
+
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ };
+
+ /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */
+
+ static uint32_t html[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ };
+
+ /* " ", """, "%", "'", %00-%1F, %7F-%FF */
+
+ static uint32_t refresh[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
+
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ };
+
+ /* " ", "%", %00-%1F */
+
+ static uint32_t memcached[] = {
+ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
+ 0x00000021, /* 0000 0000 0000 0000 0000 0000 0010 0001 */
+
+ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ /* ~}| {zyx wvut srqp onml kjih gfed cba` */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
+ };
+
+ /* mail_auth is the same as memcached */
+
+ static uint32_t *map[] =
+ { uri, args, uri_component, html, refresh, memcached, memcached };
+
+
+ escape = map[type];
+
+ if (dst == NULL) {
+
+ /* find the number of the characters to be escaped */
+
+ n = 0;
+
+ while (size) {
+ if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
+ n++;
+ }
+ src++;
+ size--;
+ }
+
+ return (uintptr_t) n;
+ }
+
+ while (size) {
+ if (escape[*src >> 5] & (1U << (*src & 0x1f))) {
+ *dst++ = '%';
+ *dst++ = hex[*src >> 4];
+ *dst++ = hex[*src & 0xf];
+ src++;
+
+ } else {
+ *dst++ = *src++;
+ }
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}
+
+
+void
+ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type)
+{
+ u_char *d, *s, ch, c, decoded;
+ enum {
+ sw_usual = 0,
+ sw_quoted,
+ sw_quoted_second
+ } state;
+
+ d = *dst;
+ s = *src;
+
+ state = 0;
+ decoded = 0;
+
+ while (size--) {
+
+ ch = *s++;
+
+ switch (state) {
+ case sw_usual:
+ if (ch == '?'
+ && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
+ {
+ *d++ = ch;
+ goto done;
+ }
+
+ if (ch == '%') {
+ state = sw_quoted;
+ break;
+ }
+
+ *d++ = ch;
+ break;
+
+ case sw_quoted:
+
+ if (ch >= '0' && ch <= '9') {
+ decoded = (u_char) (ch - '0');
+ state = sw_quoted_second;
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'f') {
+ decoded = (u_char) (c - 'a' + 10);
+ state = sw_quoted_second;
+ break;
+ }
+
+ /* the invalid quoted character */
+
+ state = sw_usual;
+
+ *d++ = ch;
+
+ break;
+
+ case sw_quoted_second:
+
+ state = sw_usual;
+
+ if (ch >= '0' && ch <= '9') {
+ ch = (u_char) ((decoded << 4) + ch - '0');
+
+ if (type & NGX_UNESCAPE_REDIRECT) {
+ if (ch > '%' && ch < 0x7f) {
+ *d++ = ch;
+ break;
+ }
+
+ *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
+
+ break;
+ }
+
+ *d++ = ch;
+
+ break;
+ }
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'f') {
+ ch = (u_char) ((decoded << 4) + c - 'a' + 10);
+
+ if (type & NGX_UNESCAPE_URI) {
+ if (ch == '?') {
+ *d++ = ch;
+ goto done;
+ }
+
+ *d++ = ch;
+ break;
+ }
+
+ if (type & NGX_UNESCAPE_REDIRECT) {
+ if (ch == '?') {
+ *d++ = ch;
+ goto done;
+ }
+
+ if (ch > '%' && ch < 0x7f) {
+ *d++ = ch;
+ break;
+ }
+
+ *d++ = '%'; *d++ = *(s - 2); *d++ = *(s - 1);
+ break;
+ }
+
+ *d++ = ch;
+
+ break;
+ }
+
+ /* the invalid quoted character */
+
+ break;
+ }
+ }
+
+done:
+
+ *dst = d;
+ *src = s;
+}
+
+
+uintptr_t
+ngx_escape_html(u_char *dst, u_char *src, size_t size)
+{
+ u_char ch;
+ ngx_uint_t len;
+
+ if (dst == NULL) {
+
+ len = 0;
+
+ while (size) {
+ switch (*src++) {
+
+ case '<':
+ len += sizeof("&lt;") - 2;
+ break;
+
+ case '>':
+ len += sizeof("&gt;") - 2;
+ break;
+
+ case '&':
+ len += sizeof("&amp;") - 2;
+ break;
+
+ case '"':
+ len += sizeof("&quot;") - 2;
+ break;
+
+ default:
+ break;
+ }
+ size--;
+ }
+
+ return (uintptr_t) len;
+ }
+
+ while (size) {
+ ch = *src++;
+
+ switch (ch) {
+
+ case '<':
+ *dst++ = '&'; *dst++ = 'l'; *dst++ = 't'; *dst++ = ';';
+ break;
+
+ case '>':
+ *dst++ = '&'; *dst++ = 'g'; *dst++ = 't'; *dst++ = ';';
+ break;
+
+ case '&':
+ *dst++ = '&'; *dst++ = 'a'; *dst++ = 'm'; *dst++ = 'p';
+ *dst++ = ';';
+ break;
+
+ case '"':
+ *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
+ *dst++ = 't'; *dst++ = ';';
+ break;
+
+ default:
+ *dst++ = ch;
+ break;
+ }
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}
+
+
+uintptr_t
+ngx_escape_json(u_char *dst, u_char *src, size_t size)
+{
+ u_char ch;
+ ngx_uint_t len;
+
+ if (dst == NULL) {
+ len = 0;
+
+ while (size) {
+ ch = *src++;
+
+ if (ch == '\\' || ch == '"') {
+ len++;
+
+ } else if (ch <= 0x1f) {
+ len += sizeof("\\u001F") - 2;
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) len;
+ }
+
+ while (size) {
+ ch = *src++;
+
+ if (ch > 0x1f) {
+
+ if (ch == '\\' || ch == '"') {
+ *dst++ = '\\';
+ }
+
+ *dst++ = ch;
+
+ } else {
+ *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
+ *dst++ = '0' + (ch >> 4);
+
+ ch &= 0xf;
+
+ *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+ }
+
+ size--;
+ }
+
+ return (uintptr_t) dst;
+}
+
+
+void
+ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_str_node_t *n, *t;
+ ngx_rbtree_node_t **p;
+
+ for ( ;; ) {
+
+ n = (ngx_str_node_t *) node;
+ t = (ngx_str_node_t *) temp;
+
+ if (node->key != temp->key) {
+
+ p = (node->key < temp->key) ? &temp->left : &temp->right;
+
+ } else if (n->str.len != t->str.len) {
+
+ p = (n->str.len < t->str.len) ? &temp->left : &temp->right;
+
+ } else {
+ p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0)
+ ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+ngx_str_node_t *
+ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_str_node_t *n;
+ ngx_rbtree_node_t *node, *sentinel;
+
+ node = rbtree->root;
+ sentinel = rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ n = (ngx_str_node_t *) node;
+
+ if (hash != node->key) {
+ node = (hash < node->key) ? node->left : node->right;
+ continue;
+ }
+
+ if (val->len != n->str.len) {
+ node = (val->len < n->str.len) ? node->left : node->right;
+ continue;
+ }
+
+ rc = ngx_memcmp(val->data, n->str.data, val->len);
+
+ if (rc < 0) {
+ node = node->left;
+ continue;
+ }
+
+ if (rc > 0) {
+ node = node->right;
+ continue;
+ }
+
+ return n;
+ }
+
+ return NULL;
+}
+
+
+/* ngx_sort() is implemented as insertion sort because we need stable sort */
+
+void
+ngx_sort(void *base, size_t n, size_t size,
+ ngx_int_t (*cmp)(const void *, const void *))
+{
+ u_char *p1, *p2, *p;
+
+ p = ngx_alloc(size, ngx_cycle->log);
+ if (p == NULL) {
+ return;
+ }
+
+ for (p1 = (u_char *) base + size;
+ p1 < (u_char *) base + n * size;
+ p1 += size)
+ {
+ ngx_memcpy(p, p1, size);
+
+ for (p2 = p1;
+ p2 > (u_char *) base && cmp(p2 - size, p) > 0;
+ p2 -= size)
+ {
+ ngx_memcpy(p2, p2 - size, size);
+ }
+
+ ngx_memcpy(p2, p, size);
+ }
+
+ ngx_free(p);
+}
+
+
+#if (NGX_MEMCPY_LIMIT)
+
+void *
+ngx_memcpy(void *dst, const void *src, size_t n)
+{
+ if (n > NGX_MEMCPY_LIMIT) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n);
+ ngx_debug_point();
+ }
+
+ return memcpy(dst, src, n);
+}
+
+#endif
diff --git a/app/nginx/src/core/ngx_string.h b/app/nginx/src/core/ngx_string.h
new file mode 100644
index 0000000..7363bd2
--- /dev/null
+++ b/app/nginx/src/core/ngx_string.h
@@ -0,0 +1,234 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_STRING_H_INCLUDED_
+#define _NGX_STRING_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ size_t len;
+ u_char *data;
+} ngx_str_t;
+
+
+typedef struct {
+ ngx_str_t key;
+ ngx_str_t value;
+} ngx_keyval_t;
+
+
+typedef struct {
+ unsigned len:28;
+
+ unsigned valid:1;
+ unsigned no_cacheable:1;
+ unsigned not_found:1;
+ unsigned escape:1;
+
+ u_char *data;
+} ngx_variable_value_t;
+
+
+#define ngx_string(str) { sizeof(str) - 1, (u_char *) str }
+#define ngx_null_string { 0, NULL }
+#define ngx_str_set(str, text) \
+ (str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
+#define ngx_str_null(str) (str)->len = 0; (str)->data = NULL
+
+
+#define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
+#define ngx_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
+
+void ngx_strlow(u_char *dst, u_char *src, size_t n);
+
+
+#define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n)
+
+
+/* msvc and icc7 compile strcmp() to inline loop */
+#define ngx_strcmp(s1, s2) strcmp((const char *) s1, (const char *) s2)
+
+
+#define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2)
+#define ngx_strlen(s) strlen((const char *) s)
+
+#define ngx_strchr(s1, c) strchr((const char *) s1, (int) c)
+
+static ngx_inline u_char *
+ngx_strlchr(u_char *p, u_char *last, u_char c)
+{
+ while (p < last) {
+
+ if (*p == c) {
+ return p;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * msvc and icc7 compile memset() to the inline "rep stos"
+ * while ZeroMemory() and bzero() are the calls.
+ * icc7 may also inline several mov's of a zeroed register for small blocks.
+ */
+#define ngx_memzero(buf, n) (void) memset(buf, 0, n)
+#define ngx_memset(buf, c, n) (void) memset(buf, c, n)
+
+
+#if (NGX_MEMCPY_LIMIT)
+
+void *ngx_memcpy(void *dst, const void *src, size_t n);
+#define ngx_cpymem(dst, src, n) (((u_char *) ngx_memcpy(dst, src, n)) + (n))
+
+#else
+
+/*
+ * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs".
+ * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es.
+ * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves.
+ */
+#define ngx_memcpy(dst, src, n) (void) memcpy(dst, src, n)
+#define ngx_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n))
+
+#endif
+
+
+#if ( __INTEL_COMPILER >= 800 )
+
+/*
+ * the simple inline cycle copies the variable length strings up to 16
+ * bytes faster than icc8 autodetecting _intel_fast_memcpy()
+ */
+
+static ngx_inline u_char *
+ngx_copy(u_char *dst, u_char *src, size_t len)
+{
+ if (len < 17) {
+
+ while (len) {
+ *dst++ = *src++;
+ len--;
+ }
+
+ return dst;
+
+ } else {
+ return ngx_cpymem(dst, src, len);
+ }
+}
+
+#else
+
+#define ngx_copy ngx_cpymem
+
+#endif
+
+
+#define ngx_memmove(dst, src, n) (void) memmove(dst, src, n)
+#define ngx_movemem(dst, src, n) (((u_char *) memmove(dst, src, n)) + (n))
+
+
+/* msvc and icc7 compile memcmp() to the inline loop */
+#define ngx_memcmp(s1, s2, n) memcmp((const char *) s1, (const char *) s2, n)
+
+
+u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n);
+u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
+u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);
+u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
+u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,
+ ...);
+u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args);
+#define ngx_vsnprintf(buf, max, fmt, args) \
+ ngx_vslprintf(buf, buf + (max), fmt, args)
+
+ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2);
+ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n);
+
+u_char *ngx_strnstr(u_char *s1, char *s2, size_t n);
+
+u_char *ngx_strstrn(u_char *s1, char *s2, size_t n);
+u_char *ngx_strcasestrn(u_char *s1, char *s2, size_t n);
+u_char *ngx_strlcasestrn(u_char *s1, u_char *last, u_char *s2, size_t n);
+
+ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n);
+ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n);
+ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2);
+ngx_int_t ngx_dns_strcmp(u_char *s1, u_char *s2);
+ngx_int_t ngx_filename_cmp(u_char *s1, u_char *s2, size_t n);
+
+ngx_int_t ngx_atoi(u_char *line, size_t n);
+ngx_int_t ngx_atofp(u_char *line, size_t n, size_t point);
+ssize_t ngx_atosz(u_char *line, size_t n);
+off_t ngx_atoof(u_char *line, size_t n);
+time_t ngx_atotm(u_char *line, size_t n);
+ngx_int_t ngx_hextoi(u_char *line, size_t n);
+
+u_char *ngx_hex_dump(u_char *dst, u_char *src, size_t len);
+
+
+#define ngx_base64_encoded_length(len) (((len + 2) / 3) * 4)
+#define ngx_base64_decoded_length(len) (((len + 3) / 4) * 3)
+
+void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
+void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src);
+ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
+ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
+
+uint32_t ngx_utf8_decode(u_char **p, size_t n);
+size_t ngx_utf8_length(u_char *p, size_t n);
+u_char *ngx_utf8_cpystrn(u_char *dst, u_char *src, size_t n, size_t len);
+
+
+#define NGX_ESCAPE_URI 0
+#define NGX_ESCAPE_ARGS 1
+#define NGX_ESCAPE_URI_COMPONENT 2
+#define NGX_ESCAPE_HTML 3
+#define NGX_ESCAPE_REFRESH 4
+#define NGX_ESCAPE_MEMCACHED 5
+#define NGX_ESCAPE_MAIL_AUTH 6
+
+#define NGX_UNESCAPE_URI 1
+#define NGX_UNESCAPE_REDIRECT 2
+
+uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
+ ngx_uint_t type);
+void ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type);
+uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size);
+uintptr_t ngx_escape_json(u_char *dst, u_char *src, size_t size);
+
+
+typedef struct {
+ ngx_rbtree_node_t node;
+ ngx_str_t str;
+} ngx_str_node_t;
+
+
+void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *name,
+ uint32_t hash);
+
+
+void ngx_sort(void *base, size_t n, size_t size,
+ ngx_int_t (*cmp)(const void *, const void *));
+#define ngx_qsort qsort
+
+
+#define ngx_value_helper(n) #n
+#define ngx_value(n) ngx_value_helper(n)
+
+
+#endif /* _NGX_STRING_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_syslog.c b/app/nginx/src/core/ngx_syslog.c
new file mode 100644
index 0000000..0a67928
--- /dev/null
+++ b/app/nginx/src/core/ngx_syslog.c
@@ -0,0 +1,382 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_SYSLOG_MAX_STR \
+ NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
+ + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
+ + 32 /* tag */ + 2 /* colon, space */
+
+
+static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
+static void ngx_syslog_cleanup(void *data);
+
+
+static char *facilities[] = {
+ "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
+ "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
+ "local1", "local2", "local3", "local4", "local5", "local6", "local7",
+ NULL
+};
+
+/* note 'error/warn' like in nginx.conf, not 'err/warning' */
+static char *severities[] = {
+ "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
+};
+
+static ngx_log_t ngx_syslog_dummy_log;
+static ngx_event_t ngx_syslog_dummy_event;
+
+
+char *
+ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ peer->pool = cf->pool;
+ peer->facility = NGX_CONF_UNSET_UINT;
+ peer->severity = NGX_CONF_UNSET_UINT;
+
+ if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->server.sockaddr == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no syslog server specified");
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->facility == NGX_CONF_UNSET_UINT) {
+ peer->facility = 23; /* local7 */
+ }
+
+ if (peer->severity == NGX_CONF_UNSET_UINT) {
+ peer->severity = 6; /* info */
+ }
+
+ if (peer->tag.data == NULL) {
+ ngx_str_set(&peer->tag, "nginx");
+ }
+
+ peer->conn.fd = (ngx_socket_t) -1;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ u_char *p, *comma, c;
+ size_t len;
+ ngx_str_t *value;
+ ngx_url_t u;
+ ngx_uint_t i;
+
+ value = cf->args->elts;
+
+ p = value[1].data + sizeof("syslog:") - 1;
+
+ for ( ;; ) {
+ comma = (u_char *) ngx_strchr(p, ',');
+
+ if (comma != NULL) {
+ len = comma - p;
+ *comma = '\0';
+
+ } else {
+ len = value[1].data + value[1].len - p;
+ }
+
+ if (ngx_strncmp(p, "server=", 7) == 0) {
+
+ if (peer->server.sockaddr != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"server\"");
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url.data = p + 7;
+ u.url.len = len - 7;
+ u.default_port = 514;
+
+ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%s in syslog server \"%V\"",
+ u.err, &u.url);
+ }
+
+ return NGX_CONF_ERROR;
+ }
+
+ peer->server = u.addrs[0];
+
+ } else if (ngx_strncmp(p, "facility=", 9) == 0) {
+
+ if (peer->facility != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"facility\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; facilities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, facilities[i]) == 0) {
+ peer->facility = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog facility \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "severity=", 9) == 0) {
+
+ if (peer->severity != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"severity\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; severities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, severities[i]) == 0) {
+ peer->severity = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog severity \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "tag=", 4) == 0) {
+
+ if (peer->tag.data != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"tag\"");
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * RFC 3164: the TAG is a string of ABNF alphanumeric characters
+ * that MUST NOT exceed 32 characters.
+ */
+ if (len - 4 > 32) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog tag length exceeds 32");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 4; i < len; i++) {
+ c = ngx_tolower(p[i]);
+
+ if (c < '0' || (c > '9' && c < 'a' && c != '_') || c > 'z') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog \"tag\" only allows "
+ "alphanumeric characters "
+ "and underscore");
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ peer->tag.data = p + 4;
+ peer->tag.len = len - 4;
+
+ } else if (len == 10 && ngx_strncmp(p, "nohostname", 10) == 0) {
+ peer->nohostname = 1;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog parameter \"%s\"", p);
+ return NGX_CONF_ERROR;
+ }
+
+ next:
+
+ if (comma == NULL) {
+ break;
+ }
+
+ p = comma + 1;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+u_char *
+ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
+{
+ ngx_uint_t pri;
+
+ pri = peer->facility * 8 + peer->severity;
+
+ if (peer->nohostname) {
+ return ngx_sprintf(buf, "<%ui>%V %V: ", pri, &ngx_cached_syslog_time,
+ &peer->tag);
+ }
+
+ return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
+ &ngx_cycle->hostname, &peer->tag);
+}
+
+
+void
+ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len)
+{
+ u_char *p, msg[NGX_SYSLOG_MAX_STR];
+ ngx_uint_t head_len;
+ ngx_syslog_peer_t *peer;
+
+ peer = log->wdata;
+
+ if (peer->busy) {
+ return;
+ }
+
+ peer->busy = 1;
+ peer->severity = level - 1;
+
+ p = ngx_syslog_add_header(peer, msg);
+ head_len = p - msg;
+
+ len -= NGX_LINEFEED_SIZE;
+
+ if (len > NGX_SYSLOG_MAX_STR - head_len) {
+ len = NGX_SYSLOG_MAX_STR - head_len;
+ }
+
+ p = ngx_snprintf(p, len, "%s", buf);
+
+ (void) ngx_syslog_send(peer, msg, p - msg);
+
+ peer->busy = 0;
+}
+
+
+ssize_t
+ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
+{
+ ssize_t n;
+
+ if (peer->conn.fd == (ngx_socket_t) -1) {
+ if (ngx_syslog_init_peer(peer) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ /* log syslog socket events with valid log */
+ peer->conn.log = ngx_cycle->log;
+
+ if (ngx_send) {
+ n = ngx_send(&peer->conn, buf, len);
+
+ } else {
+ /* event module has not yet set ngx_io */
+ n = ngx_os_io.send(&peer->conn, buf, len);
+ }
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+ if (n == NGX_ERROR && peer->server.sockaddr->sa_family == AF_UNIX) {
+
+ if (ngx_close_socket(peer->conn.fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ peer->conn.fd = (ngx_socket_t) -1;
+ }
+
+#endif
+
+ return n;
+}
+
+
+static ngx_int_t
+ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
+{
+ ngx_socket_t fd;
+ ngx_pool_cleanup_t *cln;
+
+ peer->conn.read = &ngx_syslog_dummy_event;
+ peer->conn.write = &ngx_syslog_dummy_event;
+
+ ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
+
+ fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
+ if (fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ if (ngx_nonblocking(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_nonblocking_n " failed");
+ goto failed;
+ }
+
+ if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ "connect() failed");
+ goto failed;
+ }
+
+ cln = ngx_pool_cleanup_add(peer->pool, 0);
+ if (cln == NULL) {
+ goto failed;
+ }
+
+ cln->data = peer;
+ cln->handler = ngx_syslog_cleanup;
+
+ peer->conn.fd = fd;
+
+ /* UDP sockets are always ready to write */
+ peer->conn.write->ready = 1;
+
+ return NGX_OK;
+
+failed:
+
+ if (ngx_close_socket(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ return NGX_ERROR;
+}
+
+
+static void
+ngx_syslog_cleanup(void *data)
+{
+ ngx_syslog_peer_t *peer = data;
+
+ /* prevents further use of this peer */
+ peer->busy = 1;
+
+ if (peer->conn.fd == (ngx_socket_t) -1) {
+ return;
+ }
+
+ if (ngx_close_socket(peer->conn.fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+}
diff --git a/app/nginx/src/core/ngx_syslog.h b/app/nginx/src/core/ngx_syslog.h
new file mode 100644
index 0000000..cc4c842
--- /dev/null
+++ b/app/nginx/src/core/ngx_syslog.h
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SYSLOG_H_INCLUDED_
+#define _NGX_SYSLOG_H_INCLUDED_
+
+
+typedef struct {
+ ngx_pool_t *pool;
+ ngx_uint_t facility;
+ ngx_uint_t severity;
+ ngx_str_t tag;
+
+ ngx_addr_t server;
+ ngx_connection_t conn;
+ unsigned busy:1;
+ unsigned nohostname:1;
+} ngx_syslog_peer_t;
+
+
+char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf);
+void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len);
+ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len);
+
+
+#endif /* _NGX_SYSLOG_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_thread_pool.c b/app/nginx/src/core/ngx_thread_pool.c
new file mode 100644
index 0000000..7fb0f7f
--- /dev/null
+++ b/app/nginx/src/core/ngx_thread_pool.c
@@ -0,0 +1,641 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ * Copyright (C) Valentin V. Bartenev
+ * Copyright (C) Ruslan Ermilov
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_thread_pool.h>
+
+
+typedef struct {
+ ngx_array_t pools;
+} ngx_thread_pool_conf_t;
+
+
+typedef struct {
+ ngx_thread_task_t *first;
+ ngx_thread_task_t **last;
+} ngx_thread_pool_queue_t;
+
+#define ngx_thread_pool_queue_init(q) \
+ (q)->first = NULL; \
+ (q)->last = &(q)->first
+
+
+struct ngx_thread_pool_s {
+ ngx_thread_mutex_t mtx;
+ ngx_thread_pool_queue_t queue;
+ ngx_int_t waiting;
+ ngx_thread_cond_t cond;
+
+ ngx_log_t *log;
+
+ ngx_str_t name;
+ ngx_uint_t threads;
+ ngx_int_t max_queue;
+
+ u_char *file;
+ ngx_uint_t line;
+};
+
+
+static ngx_int_t ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log,
+ ngx_pool_t *pool);
+static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp);
+static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log);
+
+static void *ngx_thread_pool_cycle(void *data);
+static void ngx_thread_pool_handler(ngx_event_t *ev);
+
+static char *ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+static void *ngx_thread_pool_create_conf(ngx_cycle_t *cycle);
+static char *ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf);
+
+static ngx_int_t ngx_thread_pool_init_worker(ngx_cycle_t *cycle);
+static void ngx_thread_pool_exit_worker(ngx_cycle_t *cycle);
+
+
+static ngx_command_t ngx_thread_pool_commands[] = {
+
+ { ngx_string("thread_pool"),
+ NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE23,
+ ngx_thread_pool,
+ 0,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_core_module_t ngx_thread_pool_module_ctx = {
+ ngx_string("thread_pool"),
+ ngx_thread_pool_create_conf,
+ ngx_thread_pool_init_conf
+};
+
+
+ngx_module_t ngx_thread_pool_module = {
+ NGX_MODULE_V1,
+ &ngx_thread_pool_module_ctx, /* module context */
+ ngx_thread_pool_commands, /* module directives */
+ NGX_CORE_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ ngx_thread_pool_init_worker, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_thread_pool_exit_worker, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_str_t ngx_thread_pool_default = ngx_string("default");
+
+static ngx_uint_t ngx_thread_pool_task_id;
+static ngx_atomic_t ngx_thread_pool_done_lock;
+static ngx_thread_pool_queue_t ngx_thread_pool_done;
+
+
+static ngx_int_t
+ngx_thread_pool_init(ngx_thread_pool_t *tp, ngx_log_t *log, ngx_pool_t *pool)
+{
+ int err;
+ pthread_t tid;
+ ngx_uint_t n;
+ pthread_attr_t attr;
+
+ if (ngx_notify == NULL) {
+ ngx_log_error(NGX_LOG_ALERT, log, 0,
+ "the configured event method cannot be used with thread pools");
+ return NGX_ERROR;
+ }
+
+ ngx_thread_pool_queue_init(&tp->queue);
+
+ if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_thread_cond_create(&tp->cond, log) != NGX_OK) {
+ (void) ngx_thread_mutex_destroy(&tp->mtx, log);
+ return NGX_ERROR;
+ }
+
+ tp->log = log;
+
+ err = pthread_attr_init(&attr);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_attr_init() failed");
+ return NGX_ERROR;
+ }
+
+ err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_attr_setdetachstate() failed");
+ return NGX_ERROR;
+ }
+
+#if 0
+ err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_attr_setstacksize() failed");
+ return NGX_ERROR;
+ }
+#endif
+
+ for (n = 0; n < tp->threads; n++) {
+ err = pthread_create(&tid, &attr, ngx_thread_pool_cycle, tp);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, log, err,
+ "pthread_create() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ (void) pthread_attr_destroy(&attr);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_thread_pool_destroy(ngx_thread_pool_t *tp)
+{
+ ngx_uint_t n;
+ ngx_thread_task_t task;
+ volatile ngx_uint_t lock;
+
+ ngx_memzero(&task, sizeof(ngx_thread_task_t));
+
+ task.handler = ngx_thread_pool_exit_handler;
+ task.ctx = (void *) &lock;
+
+ for (n = 0; n < tp->threads; n++) {
+ lock = 1;
+
+ if (ngx_thread_task_post(tp, &task) != NGX_OK) {
+ return;
+ }
+
+ while (lock) {
+ ngx_sched_yield();
+ }
+
+ task.event.active = 0;
+ }
+
+ (void) ngx_thread_cond_destroy(&tp->cond, tp->log);
+
+ (void) ngx_thread_mutex_destroy(&tp->mtx, tp->log);
+}
+
+
+static void
+ngx_thread_pool_exit_handler(void *data, ngx_log_t *log)
+{
+ ngx_uint_t *lock = data;
+
+ *lock = 0;
+
+ pthread_exit(0);
+}
+
+
+ngx_thread_task_t *
+ngx_thread_task_alloc(ngx_pool_t *pool, size_t size)
+{
+ ngx_thread_task_t *task;
+
+ task = ngx_pcalloc(pool, sizeof(ngx_thread_task_t) + size);
+ if (task == NULL) {
+ return NULL;
+ }
+
+ task->ctx = task + 1;
+
+ return task;
+}
+
+
+ngx_int_t
+ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task)
+{
+ if (task->event.active) {
+ ngx_log_error(NGX_LOG_ALERT, tp->log, 0,
+ "task #%ui already active", task->id);
+ return NGX_ERROR;
+ }
+
+ if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (tp->waiting >= tp->max_queue) {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+
+ ngx_log_error(NGX_LOG_ERR, tp->log, 0,
+ "thread pool \"%V\" queue overflow: %i tasks waiting",
+ &tp->name, tp->waiting);
+ return NGX_ERROR;
+ }
+
+ task->event.active = 1;
+
+ task->id = ngx_thread_pool_task_id++;
+ task->next = NULL;
+
+ if (ngx_thread_cond_signal(&tp->cond, tp->log) != NGX_OK) {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+ return NGX_ERROR;
+ }
+
+ *tp->queue.last = task;
+ tp->queue.last = &task->next;
+
+ tp->waiting++;
+
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "task #%ui added to thread pool \"%V\"",
+ task->id, &tp->name);
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_thread_pool_cycle(void *data)
+{
+ ngx_thread_pool_t *tp = data;
+
+ int err;
+ sigset_t set;
+ ngx_thread_task_t *task;
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "thread in pool \"%V\" started", &tp->name);
+
+ sigfillset(&set);
+
+ sigdelset(&set, SIGILL);
+ sigdelset(&set, SIGFPE);
+ sigdelset(&set, SIGSEGV);
+ sigdelset(&set, SIGBUS);
+
+ err = pthread_sigmask(SIG_BLOCK, &set, NULL);
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, tp->log, err, "pthread_sigmask() failed");
+ return NULL;
+ }
+
+ for ( ;; ) {
+ if (ngx_thread_mutex_lock(&tp->mtx, tp->log) != NGX_OK) {
+ return NULL;
+ }
+
+ /* the number may become negative */
+ tp->waiting--;
+
+ while (tp->queue.first == NULL) {
+ if (ngx_thread_cond_wait(&tp->cond, &tp->mtx, tp->log)
+ != NGX_OK)
+ {
+ (void) ngx_thread_mutex_unlock(&tp->mtx, tp->log);
+ return NULL;
+ }
+ }
+
+ task = tp->queue.first;
+ tp->queue.first = task->next;
+
+ if (tp->queue.first == NULL) {
+ tp->queue.last = &tp->queue.first;
+ }
+
+ if (ngx_thread_mutex_unlock(&tp->mtx, tp->log) != NGX_OK) {
+ return NULL;
+ }
+
+#if 0
+ ngx_time_update();
+#endif
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "run task #%ui in thread pool \"%V\"",
+ task->id, &tp->name);
+
+ task->handler(task->ctx, tp->log);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, tp->log, 0,
+ "complete task #%ui in thread pool \"%V\"",
+ task->id, &tp->name);
+
+ task->next = NULL;
+
+ ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
+
+ *ngx_thread_pool_done.last = task;
+ ngx_thread_pool_done.last = &task->next;
+
+ ngx_memory_barrier();
+
+ ngx_unlock(&ngx_thread_pool_done_lock);
+
+ (void) ngx_notify(ngx_thread_pool_handler);
+ }
+}
+
+
+static void
+ngx_thread_pool_handler(ngx_event_t *ev)
+{
+ ngx_event_t *event;
+ ngx_thread_task_t *task;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "thread pool handler");
+
+ ngx_spinlock(&ngx_thread_pool_done_lock, 1, 2048);
+
+ task = ngx_thread_pool_done.first;
+ ngx_thread_pool_done.first = NULL;
+ ngx_thread_pool_done.last = &ngx_thread_pool_done.first;
+
+ ngx_memory_barrier();
+
+ ngx_unlock(&ngx_thread_pool_done_lock);
+
+ while (task) {
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
+ "run completion handler for task #%ui", task->id);
+
+ event = &task->event;
+ task = task->next;
+
+ event->complete = 1;
+ event->active = 0;
+
+ event->handler(event);
+ }
+}
+
+
+static void *
+ngx_thread_pool_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_thread_pool_conf_t *tcf;
+
+ tcf = ngx_pcalloc(cycle->pool, sizeof(ngx_thread_pool_conf_t));
+ if (tcf == NULL) {
+ return NULL;
+ }
+
+ if (ngx_array_init(&tcf->pools, cycle->pool, 4,
+ sizeof(ngx_thread_pool_t *))
+ != NGX_OK)
+ {
+ return NULL;
+ }
+
+ return tcf;
+}
+
+
+static char *
+ngx_thread_pool_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_thread_pool_conf_t *tcf = conf;
+
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+
+ if (tpp[i]->threads) {
+ continue;
+ }
+
+ if (tpp[i]->name.len == ngx_thread_pool_default.len
+ && ngx_strncmp(tpp[i]->name.data, ngx_thread_pool_default.data,
+ ngx_thread_pool_default.len)
+ == 0)
+ {
+ tpp[i]->threads = 32;
+ tpp[i]->max_queue = 65536;
+ continue;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "unknown thread pool \"%V\" in %s:%ui",
+ &tpp[i]->name, tpp[i]->file, tpp[i]->line);
+
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_thread_pool(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_str_t *value;
+ ngx_uint_t i;
+ ngx_thread_pool_t *tp;
+
+ value = cf->args->elts;
+
+ tp = ngx_thread_pool_add(cf, &value[1]);
+
+ if (tp == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (tp->threads) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate thread pool \"%V\"", &tp->name);
+ return NGX_CONF_ERROR;
+ }
+
+ tp->max_queue = 65536;
+
+ for (i = 2; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "threads=", 8) == 0) {
+
+ tp->threads = ngx_atoi(value[i].data + 8, value[i].len - 8);
+
+ if (tp->threads == (ngx_uint_t) NGX_ERROR || tp->threads == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid threads value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "max_queue=", 10) == 0) {
+
+ tp->max_queue = ngx_atoi(value[i].data + 10, value[i].len - 10);
+
+ if (tp->max_queue == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid max_queue value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+ }
+
+ if (tp->threads == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"threads\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+ngx_thread_pool_t *
+ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name)
+{
+ ngx_thread_pool_t *tp, **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (name == NULL) {
+ name = &ngx_thread_pool_default;
+ }
+
+ tp = ngx_thread_pool_get(cf->cycle, name);
+
+ if (tp) {
+ return tp;
+ }
+
+ tp = ngx_pcalloc(cf->pool, sizeof(ngx_thread_pool_t));
+ if (tp == NULL) {
+ return NULL;
+ }
+
+ tp->name = *name;
+ tp->file = cf->conf_file->file.name.data;
+ tp->line = cf->conf_file->line;
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cf->cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ tpp = ngx_array_push(&tcf->pools);
+ if (tpp == NULL) {
+ return NULL;
+ }
+
+ *tpp = tp;
+
+ return tp;
+}
+
+
+ngx_thread_pool_t *
+ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+
+ if (tpp[i]->name.len == name->len
+ && ngx_strncmp(tpp[i]->name.data, name->data, name->len) == 0)
+ {
+ return tpp[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+static ngx_int_t
+ngx_thread_pool_init_worker(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (ngx_process != NGX_PROCESS_WORKER
+ && ngx_process != NGX_PROCESS_SINGLE)
+ {
+ return NGX_OK;
+ }
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ if (tcf == NULL) {
+ return NGX_OK;
+ }
+
+ ngx_thread_pool_queue_init(&ngx_thread_pool_done);
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+ if (ngx_thread_pool_init(tpp[i], cycle->log, cycle->pool) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_thread_pool_exit_worker(ngx_cycle_t *cycle)
+{
+ ngx_uint_t i;
+ ngx_thread_pool_t **tpp;
+ ngx_thread_pool_conf_t *tcf;
+
+ if (ngx_process != NGX_PROCESS_WORKER
+ && ngx_process != NGX_PROCESS_SINGLE)
+ {
+ return;
+ }
+
+ tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx,
+ ngx_thread_pool_module);
+
+ if (tcf == NULL) {
+ return;
+ }
+
+ tpp = tcf->pools.elts;
+
+ for (i = 0; i < tcf->pools.nelts; i++) {
+ ngx_thread_pool_destroy(tpp[i]);
+ }
+}
diff --git a/app/nginx/src/core/ngx_thread_pool.h b/app/nginx/src/core/ngx_thread_pool.h
new file mode 100644
index 0000000..5e5adf6
--- /dev/null
+++ b/app/nginx/src/core/ngx_thread_pool.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ * Copyright (C) Valentin V. Bartenev
+ */
+
+
+#ifndef _NGX_THREAD_POOL_H_INCLUDED_
+#define _NGX_THREAD_POOL_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+struct ngx_thread_task_s {
+ ngx_thread_task_t *next;
+ ngx_uint_t id;
+ void *ctx;
+ void (*handler)(void *data, ngx_log_t *log);
+ ngx_event_t event;
+};
+
+
+typedef struct ngx_thread_pool_s ngx_thread_pool_t;
+
+
+ngx_thread_pool_t *ngx_thread_pool_add(ngx_conf_t *cf, ngx_str_t *name);
+ngx_thread_pool_t *ngx_thread_pool_get(ngx_cycle_t *cycle, ngx_str_t *name);
+
+ngx_thread_task_t *ngx_thread_task_alloc(ngx_pool_t *pool, size_t size);
+ngx_int_t ngx_thread_task_post(ngx_thread_pool_t *tp, ngx_thread_task_t *task);
+
+
+#endif /* _NGX_THREAD_POOL_H_INCLUDED_ */
diff --git a/app/nginx/src/core/ngx_times.c b/app/nginx/src/core/ngx_times.c
new file mode 100644
index 0000000..843314a
--- /dev/null
+++ b/app/nginx/src/core/ngx_times.c
@@ -0,0 +1,428 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+/*
+ * The time may be updated by signal handler or by several threads.
+ * The time update operations are rare and require to hold the ngx_time_lock.
+ * The time read operations are frequent, so they are lock-free and get time
+ * values and strings from the current slot. Thus thread may get the corrupted
+ * values only if it is preempted while copying and then it is not scheduled
+ * to run more than NGX_TIME_SLOTS seconds.
+ */
+
+#define NGX_TIME_SLOTS 64
+
+static ngx_uint_t slot;
+static ngx_atomic_t ngx_time_lock;
+
+volatile ngx_msec_t ngx_current_msec;
+volatile ngx_time_t *ngx_cached_time;
+volatile ngx_str_t ngx_cached_err_log_time;
+volatile ngx_str_t ngx_cached_http_time;
+volatile ngx_str_t ngx_cached_http_log_time;
+volatile ngx_str_t ngx_cached_http_log_iso8601;
+volatile ngx_str_t ngx_cached_syslog_time;
+
+#if !(NGX_WIN32)
+
+/*
+ * localtime() and localtime_r() are not Async-Signal-Safe functions, therefore,
+ * they must not be called by a signal handler, so we use the cached
+ * GMT offset value. Fortunately the value is changed only two times a year.
+ */
+
+static ngx_int_t cached_gmtoff;
+#endif
+
+static ngx_time_t cached_time[NGX_TIME_SLOTS];
+static u_char cached_err_log_time[NGX_TIME_SLOTS]
+ [sizeof("1970/09/28 12:00:00")];
+static u_char cached_http_time[NGX_TIME_SLOTS]
+ [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")];
+static u_char cached_http_log_time[NGX_TIME_SLOTS]
+ [sizeof("28/Sep/1970:12:00:00 +0600")];
+static u_char cached_http_log_iso8601[NGX_TIME_SLOTS]
+ [sizeof("1970-09-28T12:00:00+06:00")];
+static u_char cached_syslog_time[NGX_TIME_SLOTS]
+ [sizeof("Sep 28 12:00:00")];
+
+
+static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+void
+ngx_time_init(void)
+{
+ ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1;
+ ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
+ ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
+ ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
+ ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
+
+ ngx_cached_time = &cached_time[0];
+
+ ngx_time_update();
+}
+
+
+void
+ngx_time_update(void)
+{
+ u_char *p0, *p1, *p2, *p3, *p4;
+ ngx_tm_t tm, gmt;
+ time_t sec;
+ ngx_uint_t msec;
+ ngx_time_t *tp;
+ struct timeval tv;
+
+ if (!ngx_trylock(&ngx_time_lock)) {
+ return;
+ }
+
+ ngx_gettimeofday(&tv);
+
+ sec = tv.tv_sec;
+ msec = tv.tv_usec / 1000;
+
+ ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
+
+ tp = &cached_time[slot];
+
+ if (tp->sec == sec) {
+ tp->msec = msec;
+ ngx_unlock(&ngx_time_lock);
+ return;
+ }
+
+ if (slot == NGX_TIME_SLOTS - 1) {
+ slot = 0;
+ } else {
+ slot++;
+ }
+
+ tp = &cached_time[slot];
+
+ tp->sec = sec;
+ tp->msec = msec;
+
+ ngx_gmtime(sec, &gmt);
+
+
+ p0 = &cached_http_time[slot][0];
+
+ (void) ngx_sprintf(p0, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+ week[gmt.ngx_tm_wday], gmt.ngx_tm_mday,
+ months[gmt.ngx_tm_mon - 1], gmt.ngx_tm_year,
+ gmt.ngx_tm_hour, gmt.ngx_tm_min, gmt.ngx_tm_sec);
+
+#if (NGX_HAVE_GETTIMEZONE)
+
+ tp->gmtoff = ngx_gettimezone();
+ ngx_gmtime(sec + tp->gmtoff * 60, &tm);
+
+#elif (NGX_HAVE_GMTOFF)
+
+ ngx_localtime(sec, &tm);
+ cached_gmtoff = (ngx_int_t) (tm.ngx_tm_gmtoff / 60);
+ tp->gmtoff = cached_gmtoff;
+
+#else
+
+ ngx_localtime(sec, &tm);
+ cached_gmtoff = ngx_timezone(tm.ngx_tm_isdst);
+ tp->gmtoff = cached_gmtoff;
+
+#endif
+
+
+ p1 = &cached_err_log_time[slot][0];
+
+ (void) ngx_sprintf(p1, "%4d/%02d/%02d %02d:%02d:%02d",
+ tm.ngx_tm_year, tm.ngx_tm_mon,
+ tm.ngx_tm_mday, tm.ngx_tm_hour,
+ tm.ngx_tm_min, tm.ngx_tm_sec);
+
+
+ p2 = &cached_http_log_time[slot][0];
+
+ (void) ngx_sprintf(p2, "%02d/%s/%d:%02d:%02d:%02d %c%02i%02i",
+ tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
+ tm.ngx_tm_year, tm.ngx_tm_hour,
+ tm.ngx_tm_min, tm.ngx_tm_sec,
+ tp->gmtoff < 0 ? '-' : '+',
+ ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
+
+ p3 = &cached_http_log_iso8601[slot][0];
+
+ (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02i:%02i",
+ tm.ngx_tm_year, tm.ngx_tm_mon,
+ tm.ngx_tm_mday, tm.ngx_tm_hour,
+ tm.ngx_tm_min, tm.ngx_tm_sec,
+ tp->gmtoff < 0 ? '-' : '+',
+ ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
+
+ p4 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+
+ ngx_memory_barrier();
+
+ ngx_cached_time = tp;
+ ngx_cached_http_time.data = p0;
+ ngx_cached_err_log_time.data = p1;
+ ngx_cached_http_log_time.data = p2;
+ ngx_cached_http_log_iso8601.data = p3;
+ ngx_cached_syslog_time.data = p4;
+
+ ngx_unlock(&ngx_time_lock);
+}
+
+
+#if !(NGX_WIN32)
+
+void
+ngx_time_sigsafe_update(void)
+{
+ u_char *p, *p2;
+ ngx_tm_t tm;
+ time_t sec;
+ ngx_time_t *tp;
+ struct timeval tv;
+
+ if (!ngx_trylock(&ngx_time_lock)) {
+ return;
+ }
+
+ ngx_gettimeofday(&tv);
+
+ sec = tv.tv_sec;
+
+ tp = &cached_time[slot];
+
+ if (tp->sec == sec) {
+ ngx_unlock(&ngx_time_lock);
+ return;
+ }
+
+ if (slot == NGX_TIME_SLOTS - 1) {
+ slot = 0;
+ } else {
+ slot++;
+ }
+
+ tp = &cached_time[slot];
+
+ tp->sec = 0;
+
+ ngx_gmtime(sec + cached_gmtoff * 60, &tm);
+
+ p = &cached_err_log_time[slot][0];
+
+ (void) ngx_sprintf(p, "%4d/%02d/%02d %02d:%02d:%02d",
+ tm.ngx_tm_year, tm.ngx_tm_mon,
+ tm.ngx_tm_mday, tm.ngx_tm_hour,
+ tm.ngx_tm_min, tm.ngx_tm_sec);
+
+ p2 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+
+ ngx_memory_barrier();
+
+ ngx_cached_err_log_time.data = p;
+ ngx_cached_syslog_time.data = p2;
+
+ ngx_unlock(&ngx_time_lock);
+}
+
+#endif
+
+
+u_char *
+ngx_http_time(u_char *buf, time_t t)
+{
+ ngx_tm_t tm;
+
+ ngx_gmtime(t, &tm);
+
+ return ngx_sprintf(buf, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+ week[tm.ngx_tm_wday],
+ tm.ngx_tm_mday,
+ months[tm.ngx_tm_mon - 1],
+ tm.ngx_tm_year,
+ tm.ngx_tm_hour,
+ tm.ngx_tm_min,
+ tm.ngx_tm_sec);
+}
+
+
+u_char *
+ngx_http_cookie_time(u_char *buf, time_t t)
+{
+ ngx_tm_t tm;
+
+ ngx_gmtime(t, &tm);
+
+ /*
+ * Netscape 3.x does not understand 4-digit years at all and
+ * 2-digit years more than "37"
+ */
+
+ return ngx_sprintf(buf,
+ (tm.ngx_tm_year > 2037) ?
+ "%s, %02d-%s-%d %02d:%02d:%02d GMT":
+ "%s, %02d-%s-%02d %02d:%02d:%02d GMT",
+ week[tm.ngx_tm_wday],
+ tm.ngx_tm_mday,
+ months[tm.ngx_tm_mon - 1],
+ (tm.ngx_tm_year > 2037) ? tm.ngx_tm_year:
+ tm.ngx_tm_year % 100,
+ tm.ngx_tm_hour,
+ tm.ngx_tm_min,
+ tm.ngx_tm_sec);
+}
+
+
+void
+ngx_gmtime(time_t t, ngx_tm_t *tp)
+{
+ ngx_int_t yday;
+ ngx_uint_t n, sec, min, hour, mday, mon, year, wday, days, leap;
+
+ /* the calculation is valid for positive time_t only */
+
+ n = (ngx_uint_t) t;
+
+ days = n / 86400;
+
+ /* January 1, 1970 was Thursday */
+
+ wday = (4 + days) % 7;
+
+ n %= 86400;
+ hour = n / 3600;
+ n %= 3600;
+ min = n / 60;
+ sec = n % 60;
+
+ /*
+ * the algorithm based on Gauss' formula,
+ * see src/http/ngx_http_parse_time.c
+ */
+
+ /* days since March 1, 1 BC */
+ days = days - (31 + 28) + 719527;
+
+ /*
+ * The "days" should be adjusted to 1 only, however, some March 1st's go
+ * to previous year, so we adjust them to 2. This causes also shift of the
+ * last February days to next year, but we catch the case when "yday"
+ * becomes negative.
+ */
+
+ year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1);
+
+ yday = days - (365 * year + year / 4 - year / 100 + year / 400);
+
+ if (yday < 0) {
+ leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0));
+ yday = 365 + leap + yday;
+ year--;
+ }
+
+ /*
+ * The empirical formula that maps "yday" to month.
+ * There are at least 10 variants, some of them are:
+ * mon = (yday + 31) * 15 / 459
+ * mon = (yday + 31) * 17 / 520
+ * mon = (yday + 31) * 20 / 612
+ */
+
+ mon = (yday + 31) * 10 / 306;
+
+ /* the Gauss' formula that evaluates days before the month */
+
+ mday = yday - (367 * mon / 12 - 30) + 1;
+
+ if (yday >= 306) {
+
+ year++;
+ mon -= 10;
+
+ /*
+ * there is no "yday" in Win32 SYSTEMTIME
+ *
+ * yday -= 306;
+ */
+
+ } else {
+
+ mon += 2;
+
+ /*
+ * there is no "yday" in Win32 SYSTEMTIME
+ *
+ * yday += 31 + 28 + leap;
+ */
+ }
+
+ tp->ngx_tm_sec = (ngx_tm_sec_t) sec;
+ tp->ngx_tm_min = (ngx_tm_min_t) min;
+ tp->ngx_tm_hour = (ngx_tm_hour_t) hour;
+ tp->ngx_tm_mday = (ngx_tm_mday_t) mday;
+ tp->ngx_tm_mon = (ngx_tm_mon_t) mon;
+ tp->ngx_tm_year = (ngx_tm_year_t) year;
+ tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
+}
+
+
+time_t
+ngx_next_time(time_t when)
+{
+ time_t now, next;
+ struct tm tm;
+
+ now = ngx_time();
+
+ ngx_libc_localtime(now, &tm);
+
+ tm.tm_hour = (int) (when / 3600);
+ when %= 3600;
+ tm.tm_min = (int) (when / 60);
+ tm.tm_sec = (int) (when % 60);
+
+ next = mktime(&tm);
+
+ if (next == -1) {
+ return -1;
+ }
+
+ if (next - now > 0) {
+ return next;
+ }
+
+ tm.tm_mday++;
+
+ /* mktime() should normalize a date (Jan 32, etc) */
+
+ next = mktime(&tm);
+
+ if (next != -1) {
+ return next;
+ }
+
+ return -1;
+}
diff --git a/app/nginx/src/core/ngx_times.h b/app/nginx/src/core/ngx_times.h
new file mode 100644
index 0000000..94aedcd
--- /dev/null
+++ b/app/nginx/src/core/ngx_times.h
@@ -0,0 +1,52 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_TIMES_H_INCLUDED_
+#define _NGX_TIMES_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+typedef struct {
+ time_t sec;
+ ngx_uint_t msec;
+ ngx_int_t gmtoff;
+} ngx_time_t;
+
+
+void ngx_time_init(void);
+void ngx_time_update(void);
+void ngx_time_sigsafe_update(void);
+u_char *ngx_http_time(u_char *buf, time_t t);
+u_char *ngx_http_cookie_time(u_char *buf, time_t t);
+void ngx_gmtime(time_t t, ngx_tm_t *tp);
+
+time_t ngx_next_time(time_t when);
+#define ngx_next_time_n "mktime()"
+
+
+extern volatile ngx_time_t *ngx_cached_time;
+
+#define ngx_time() ngx_cached_time->sec
+#define ngx_timeofday() (ngx_time_t *) ngx_cached_time
+
+extern volatile ngx_str_t ngx_cached_err_log_time;
+extern volatile ngx_str_t ngx_cached_http_time;
+extern volatile ngx_str_t ngx_cached_http_log_time;
+extern volatile ngx_str_t ngx_cached_http_log_iso8601;
+extern volatile ngx_str_t ngx_cached_syslog_time;
+
+/*
+ * milliseconds elapsed since epoch and truncated to ngx_msec_t,
+ * used in event timers
+ */
+extern volatile ngx_msec_t ngx_current_msec;
+
+
+#endif /* _NGX_TIMES_H_INCLUDED_ */