diff src/http/ngx_http.c @ 142:84910468f6de NGINX_0_3_18

nginx 0.3.18 *) Feature: the "server_names" directive supports the ".domain.tld" names. *) Feature: the "server_names" directive uses the hash for the "*.domain.tld" names and more effective hash for usual names. *) Change: the "server_names_hash_max_size" and "server_names_hash_bucket_size" directives. *) Change: the "server_names_hash" and "server_names_hash_threshold" directives were canceled. *) Feature: the "valid_referers" directive uses the hash site names. *) Change: now the "valid_referers" directive checks the site names only without the URI part. *) Bugfix: some ".domain.tld" names incorrectly processed by the ngx_http_map_module. *) Bugfix: segmentation fault was occurred if configuration file did not exist; bug appeared in 0.3.12. *) Bugfix: on 64-bit platforms segmentation fault may occurred on start; bug appeared in 0.3.16.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 Dec 2005 00:00:00 +0300
parents 8e6d4d96ec4c
children e1c6ac408b68
line wrap: on
line diff
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -14,18 +14,22 @@ static char *ngx_http_block(ngx_conf_t *
 static int ngx_libc_cdecl ngx_cmp_server_names(const void *one,
     const void *two);
 static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
-    ngx_http_in_port_t *in_port, ngx_http_listen_t *lscf,
+    ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf,
     ngx_http_core_srv_conf_t *cscf);
 static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
-    ngx_http_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf);
+    ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf);
 static char *ngx_http_merge_locations(ngx_conf_t *cf,
     ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module,
     ngx_uint_t ctx_index);
-
-ngx_uint_t  ngx_http_max_module;
+static int ngx_libc_cdecl ngx_http_cmp_conf_in_addrs(const void *one,
+    const void *two);
+static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
+    const void *two);
 
-ngx_uint_t  ngx_http_total_requests;
-uint64_t    ngx_http_total_sent;
+ngx_uint_t   ngx_http_max_module;
+
+ngx_uint_t   ngx_http_total_requests;
+uint64_t     ngx_http_total_sent;
 
 
 ngx_int_t  (*ngx_http_top_header_filter) (ngx_http_request_t *r);
@@ -72,19 +76,24 @@ static char *
 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char                        *rv;
-    ngx_uint_t                   mi, m, s, l, p, a, n, key;
-    ngx_uint_t                   port_found, addr_found;
-    ngx_uint_t                   virtual_names, separate_binding;
+    u_char                       ch;
+    ngx_int_t                    rc;
+    ngx_uint_t                   mi, m, s, l, p, a, n, i;
+    ngx_uint_t                   last, bind_all, done;
     ngx_conf_t                   pcf;
     ngx_array_t                  in_ports;
+    ngx_hash_init_t              hash;
     ngx_listening_t             *ls;
     ngx_http_listen_t           *lscf;
     ngx_http_module_t           *module;
+    ngx_http_in_port_t          *hip;
     ngx_http_handler_pt         *h;
     ngx_http_conf_ctx_t         *ctx;
-    ngx_http_in_port_t          *in_port, *inport;
-    ngx_http_in_addr_t          *in_addr, *inaddr;
-    ngx_http_server_name_t      *s_name, *name;
+    ngx_http_conf_in_port_t     *in_port;
+    ngx_http_conf_in_addr_t     *in_addr;
+    ngx_hash_keys_arrays_t       ha;
+    ngx_http_server_name_t      *name;
+    ngx_http_virtual_names_t    *vn;
     ngx_http_core_srv_conf_t   **cscfp, *cscf;
     ngx_http_core_loc_conf_t    *clcf;
     ngx_http_core_main_conf_t   *cmcf;
@@ -414,7 +423,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
      * to quickly find the server core module configuration at run-time
      */
 
-    if (ngx_array_init(&in_ports, cf->pool, 2, sizeof(ngx_http_in_port_t))
+    if (ngx_array_init(&in_ports, cf->temp_pool, 2,
+                       sizeof(ngx_http_conf_in_port_t))
         != NGX_OK)
     {
         return NGX_CONF_ERROR;
@@ -430,137 +440,85 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         lscf = cscfp[s]->listen.elts;
         for (l = 0; l < cscfp[s]->listen.nelts; l++) {
 
-            port_found = 0;
-
             /* AF_INET only */
 
             in_port = in_ports.elts;
             for (p = 0; p < in_ports.nelts; p++) {
 
-                if (lscf[l].port == in_port[p].port) {
+                if (lscf[l].port != in_port[p].port) {
+                    continue;
+                }
 
-                    /* the port is already in the port list */
-
-                    port_found = 1;
-                    addr_found = 0;
+                /* the port is already in the port list */
 
-                    in_addr = in_port[p].addrs.elts;
-                    for (a = 0; a < in_port[p].addrs.nelts; a++) {
+                in_addr = in_port[p].addrs.elts;
+                for (a = 0; a < in_port[p].addrs.nelts; a++) {
 
-                        if (lscf[l].addr == in_addr[a].addr) {
+                    if (lscf[l].addr != in_addr[a].addr) {
+                        continue;
+                    }
 
-                            /* the address is already in the address list */
+                    /* the address is already in the address list */
 
-                            if (ngx_http_add_names(cf, &in_addr[a], cscfp[s])
-                                != NGX_OK)
-                            {
-                                return NGX_CONF_ERROR;
-                            }
+                    if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK)
+                    {
+                        return NGX_CONF_ERROR;
+                    }
 
-                            /*
-                             * check the duplicate "default" server
-                             * for this address:port
-                             */
+                    /*
+                     * check the duplicate "default" server
+                     * for this address:port
+                     */
 
-                            if (lscf[l].conf.default_server) {
+                    if (lscf[l].conf.default_server) {
 
-                                if (in_addr[a].conf.default_server) {
-                                    ngx_log_error(NGX_LOG_ERR, cf->log, 0,
+                        if (in_addr[a].default_server) {
+                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                         "the duplicate default server in %V:%d",
                                         &lscf[l].file_name, lscf[l].line);
 
-                                    return NGX_CONF_ERROR;
-                                }
-
-                                in_addr[a].core_srv_conf = cscfp[s];
-                                in_addr[a].conf.default_server = 1;
-                            }
-
-                            addr_found = 1;
-
-                            break;
-
-                        } else if (in_addr[a].addr == INADDR_ANY) {
-
-                            /* the INADDR_ANY is always the last address */
-
-                            inaddr = ngx_array_push(&in_port[p].addrs);
-                            if (inaddr == NULL) {
-                                return NGX_CONF_ERROR;
-                            }
-                            in_addr = in_port[p].addrs.elts;
+                            return NGX_CONF_ERROR;
+                        }
 
-                            /*
-                             * the INADDR_ANY must be the last resort
-                             * so we move it to the end of the address list
-                             * and put the new address in its place
-                             */
-
-                            ngx_memcpy(inaddr, &in_addr[a],
-                                       sizeof(ngx_http_in_addr_t));
-
-                            in_addr[a].addr = lscf[l].addr;
-                            in_addr[a].names.elts = NULL;
-                            in_addr[a].hash = NULL;
-                            in_addr[a].wildcards.elts = NULL;
-                            in_addr[a].core_srv_conf = cscfp[s];
-                            in_addr[a].conf = lscf[l].conf;
-
-                            if (ngx_http_add_names(cf, &in_addr[a], cscfp[s])
-                                != NGX_OK)
-                            {
-                                return NGX_CONF_ERROR;
-                            }
-
-                            addr_found = 1;
-
-                            break;
-                        }
+                        in_addr[a].core_srv_conf = cscfp[s];
+                        in_addr[a].default_server = 1;
                     }
 
-                    if (!addr_found) {
-
-                        /*
-                         * add the address to the addresses list that
-                         * bound to this port
-                         */
-
-                        if (ngx_http_add_address(cf, &in_port[p], &lscf[l],
-                                                 cscfp[s]) != NGX_OK)
-                        {
-                            return NGX_CONF_ERROR;
-                        }
-                    }
-                }
-            }
-
-            if (!port_found) {
-
-                /* add the port to the in_port list */
-
-                in_port = ngx_array_push(&in_ports);
-                if (in_port == NULL) {
-                    return NGX_CONF_ERROR;
+                    goto found;
                 }
 
-                in_port->port = lscf[l].port;
-                in_port->addrs.elts = NULL;
+                /*
+                 * add the address to the addresses list that
+                 * bound to this port
+                 */
 
-                in_port->port_text.data = ngx_palloc(cf->pool, 7);
-                if (in_port->port_text.data == NULL) {
-                    return NGX_CONF_ERROR;
-                }
-
-                in_port->port_text.len = ngx_sprintf(in_port->port_text.data,
-                                                     ":%d", in_port->port)
-                                         - in_port->port_text.data;
-
-                if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s])
+                if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s])
                     != NGX_OK)
                 {
                     return NGX_CONF_ERROR;
                 }
+
+                goto found;
             }
+
+            /* add the port to the in_port list */
+
+            in_port = ngx_array_push(&in_ports);
+            if (in_port == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            in_port->port = lscf[l].port;
+            in_port->addrs.elts = NULL;
+
+            if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK)
+            {
+                return NGX_CONF_ERROR;
+            }
+
+        found:
+
+            continue;
         }
     }
 
@@ -572,7 +530,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     in_port = in_ports.elts;
     for (p = 0; p < in_ports.nelts; p++) {
 
-        separate_binding = 0;
+        ngx_qsort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
+                  sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs);
 
         /*
          * check whether all name-based servers have the same configuraiton
@@ -582,33 +541,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
         in_addr = in_port[p].addrs.elts;
         for (a = 0; a < in_port[p].addrs.nelts; a++) {
 
-            if (in_addr[a].conf.bind) {
-                separate_binding = 1;
-            }
-
-            virtual_names = 0;
-
             name = in_addr[a].names.elts;
             for (n = 0; n < in_addr[a].names.nelts; n++) {
                 if (in_addr[a].core_srv_conf != name[n].core_srv_conf
                     || name[n].core_srv_conf->restrict_host_names
                        != NGX_HTTP_RESTRICT_HOST_OFF)
                 {
-                    virtual_names = 1;
-                    break;
-                }
-            }
-
-            if (!virtual_names) {
-                name = in_addr[a].wildcards.elts;
-                for (n = 0; n < in_addr[a].wildcards.nelts; n++) {
-                    if (in_addr[a].core_srv_conf != name[n].core_srv_conf
-                        || name[n].core_srv_conf->restrict_host_names
-                           != NGX_HTTP_RESTRICT_HOST_OFF)
-                    {
-                        virtual_names = 1;
-                        break;
-                    }
+                    goto virtual_names;
                 }
             }
 
@@ -618,65 +557,132 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
              * then we do not need to check them at run-time at all
              */
 
-            if (!virtual_names) {
-                in_addr[a].names.nelts = 0;
-                continue;
+            in_addr[a].names.nelts = 0;
+
+            continue;
+
+        virtual_names:
+
+            ha.temp_pool = ngx_create_pool(16384, cf->log);
+            if (ha.temp_pool == NULL) {
+                return NGX_CONF_ERROR;
             }
 
+            ha.pool = cf->pool;
 
-            ngx_qsort(in_addr[a].names.elts, in_addr[a].names.nelts,
-                      sizeof(ngx_http_server_name_t), ngx_cmp_server_names);
+            if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
+                ngx_destroy_pool(ha.temp_pool);
+                return NGX_CONF_ERROR;
+            }
 
+            name = in_addr[a].names.elts;
+            for (s = 0; s < in_addr[a].names.nelts; s++) {
 
-            /* create a hash for many names */
+                ch = name[s].name.data[0];
 
-            if (in_addr[a].names.nelts > cmcf->server_names_hash_threshold) {
-                in_addr[a].hash = ngx_palloc(cf->pool,
-                                             cmcf->server_names_hash
-                                                        * sizeof(ngx_array_t));
-                if (in_addr[a].hash == NULL) {
+                if (ch == '*' || ch == '.') {
+                    continue;
+                }
+
+                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
+                                      0);
+
+                if (rc == NGX_ERROR) {
                     return NGX_CONF_ERROR;
                 }
 
-                for (n = 0; n < cmcf->server_names_hash; n++) {
-                    if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 4,
-                                     sizeof(ngx_http_server_name_t)) != NGX_OK)
-                    {
-                        return NGX_CONF_ERROR;
-                    }
+                if (rc == NGX_BUSY) {
+                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                                  "conflicting server name \"%V\", ignored",
+                                  &name[s].name);
+                }
+            }
+
+            for (s = 0; s < in_addr[a].names.nelts; s++) {
+
+                ch = name[s].name.data[0];
+
+                if (ch != '*' && ch != '.') {
+                    continue;
+                }
+
+                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
+                                      NGX_HASH_WILDCARD_KEY);
+
+                if (rc == NGX_ERROR) {
+                    return NGX_CONF_ERROR;
                 }
 
-                name = in_addr[a].names.elts;
-                for (s = 0; s < in_addr[a].names.nelts; s++) {
-                    ngx_http_server_names_hash_key(key, name[s].name.data,
-                                                   name[s].name.len,
-                                                   cmcf->server_names_hash);
+                if (rc == NGX_BUSY) {
+                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                                  "conflicting server name \"%V\", ignored",
+                                  &name[s].name);
+                }
+            }
 
-                    s_name = ngx_array_push(&in_addr[a].hash[key]);
-                    if (s_name == NULL) {
-                        return NGX_CONF_ERROR;
-                    }
-                    name = in_addr[a].names.elts;
+            hash.key = ngx_hash_key_lc;
+            hash.max_size = cmcf->server_names_hash_max_size;
+            hash.bucket_size = cmcf->server_names_hash_bucket_size;
+            hash.name = "server_names_hash";
+            hash.pool = cf->pool;
 
-                    *s_name = name[s];
+            if (ha.keys.nelts) {
+                hash.hash = &in_addr[a].hash;
+                hash.temp_pool = NULL;
+
+                if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK)
+                {
+                    ngx_destroy_pool(ha.temp_pool);
+                    return NGX_CONF_ERROR;
                 }
             }
+
+            if (ha.dns_wildcards.nelts) {
+
+                ngx_qsort(ha.dns_wildcards.elts,
+                          (size_t) ha.dns_wildcards.nelts,
+                          sizeof(ngx_hash_key_t),
+                          ngx_http_cmp_dns_wildcards);
+
+                hash.hash = NULL;
+                hash.temp_pool = ha.temp_pool;
+
+                if (ngx_hash_wildcard_init(&hash, ha.dns_wildcards.elts,
+                                           ha.dns_wildcards.nelts)
+                    != NGX_OK)
+                {
+                    ngx_destroy_pool(ha.temp_pool);
+                    return NGX_CONF_ERROR;
+                }
+
+                in_addr[a].dns_wildcards = (ngx_hash_wildcard_t *) hash.hash;
+            }
+
+            ngx_destroy_pool(ha.temp_pool);
         }
 
+        in_addr = in_port[p].addrs.elts;
+        last = in_port[p].addrs.nelts;
+
         /*
          * if there is the binding to the "*:port" then we need to bind()
          * to the "*:port" only and ignore the other bindings
          */
 
-        if (in_addr[a - 1].addr == INADDR_ANY && !separate_binding) {
-            a--;
+        if (in_addr[last - 1].addr == INADDR_ANY) {
+            in_addr[last - 1].bind = 1;
+            bind_all = 0;
 
         } else {
-            a = 0;
+            bind_all = 1;
         }
 
-        in_addr = in_port[p].addrs.elts;
-        while (a < in_port[p].addrs.nelts) {
+        for (a = 0; a < last; /* void */ ) {
+
+            if (!bind_all && !in_addr[a].bind) {
+                a++;
+                continue;
+            }
 
             ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
                                                   in_port[p].port);
@@ -705,68 +711,98 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
             }
 #endif
 
-            ls->backlog = in_addr[a].conf.backlog;
-            ls->rcvbuf = in_addr[a].conf.rcvbuf;
-            ls->sndbuf = in_addr[a].conf.sndbuf;
+            ls->backlog = in_addr[a].listen_conf->backlog;
+            ls->rcvbuf = in_addr[a].listen_conf->rcvbuf;
+            ls->sndbuf = in_addr[a].listen_conf->sndbuf;
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
-            ls->accept_filter = in_addr[a].conf.accept_filter;
+            ls->accept_filter = in_addr[a].listen_conf->accept_filter;
 #endif
 
 #if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
-            ls->deferred_accept = in_addr[a].conf.deferred_accept;
+            ls->deferred_accept = in_addr[a].listen_conf->deferred_accept;
 #endif
 
             ls->ctx = ctx;
 
-            if (in_port[p].addrs.nelts > 1) {
-
-                in_addr = in_port[p].addrs.elts;
-                if (in_addr[in_port[p].addrs.nelts - 1].addr != INADDR_ANY) {
+            hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t));
+            if (hip == NULL) {
+                return NGX_CONF_ERROR;
+            }
 
-                    /*
-                     * if this port has not the "*:port" binding then create
-                     * the separate ngx_http_in_port_t for the all bindings
-                     */
+            hip->port = in_port[p].port;
+
+            hip->port_text.data = ngx_palloc(cf->pool, 7);
+            if (hip->port_text.data == NULL) {
+                return NGX_CONF_ERROR;
+            }
 
-                    inport = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t));
-                    if (inport == NULL) {
-                        return NGX_CONF_ERROR;
-                    }
+            ls->servers = hip;
+
+            hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d",
+                                             hip->port)
+                                 - hip->port_text.data;
 
-                    inport->port = in_port[p].port;
-                    inport->port_text = in_port[p].port_text;
+            in_addr = in_port[p].addrs.elts;
 
-                    /* init list of the addresses ... */
+            if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
+                hip->naddrs = 1;
+                done = 0;
 
-                    if (ngx_array_init(&inport->addrs, cf->pool, 1,
-                                       sizeof(ngx_http_in_addr_t)) != NGX_OK)
-                    {
-                        return NGX_CONF_ERROR;
-                    }
+            } else if (in_port[p].addrs.nelts > 1
+                       && in_addr[last - 1].addr == INADDR_ANY)
+            {
+                hip->naddrs = last;
+                done = 1;
 
-                    /* ... and set up it with the first address */
-
-                    inport->addrs.nelts = 1;
-                    inport->addrs.elts = in_port[p].addrs.elts;
+            } else {
+                hip->naddrs = 1;
+                done = 0;
+            }
 
-                    ls->servers = inport;
-
-                    /* prepare for the next cycle */
+#if 0
+            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
+                          "%ui: %V %d %ui %ui",
+                          a, &ls->addr_text, in_addr[a].bind,
+                          hip->naddrs, last);
+#endif
 
-                    in_port[p].addrs.elts = (char *) in_port[p].addrs.elts
-                                                      + in_port[p].addrs.size;
-                    in_port[p].addrs.nelts--;
+            hip->addrs = ngx_pcalloc(cf->pool,
+                                     hip->naddrs * sizeof(ngx_http_in_addr_t));
+            if (hip->addrs == NULL) {
+                return NGX_CONF_ERROR;
+            }
 
-                    in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts;
-                    a = 0;
+            for (i = 0; i < hip->naddrs; i++) {
+                hip->addrs[i].addr = in_addr[i].addr;
+                hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf;
 
+                if (in_addr[i].hash.buckets == NULL
+                    && (in_addr[i].dns_wildcards == NULL
+                        || in_addr[i].dns_wildcards->hash.buckets == NULL))
+                {
                     continue;
                 }
+
+                vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
+                if (vn == NULL) {
+                    return NGX_CONF_ERROR;
+                }
+                hip->addrs[i].virtual_names = vn;
+
+                vn->hash = in_addr[i].hash;
+                vn->dns_wildcards = in_addr[i].dns_wildcards;
             }
 
-            ls->servers = &in_port[p];
-            a++;
+            if (done) {
+                break;
+            }
+
+            in_addr++;
+            in_port[p].addrs.elts = in_addr;
+            last--;
+
+            a = 0;
         }
     }
 
@@ -785,12 +821,12 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
             ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                            "%s:%d %p",
                            address, in_port[p].port, in_addr[a].core_srv_conf);
-            s_name = in_addr[a].names.elts;
+            name = in_addr[a].names.elts;
             for (n = 0; n < in_addr[a].names.nelts; n++) {
                  ngx_log_debug4(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                                 "%s:%d %V %p",
-                                address, in_port[p].port, &s_name[n].name,
-                                s_name[n].core_srv_conf);
+                                address, in_port[p].port, &name[n].name,
+                                name[n].core_srv_conf);
             }
         }
     }
@@ -801,30 +837,20 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 }
 
 
-static int ngx_libc_cdecl
-ngx_cmp_server_names(const void *one, const void *two)
-{
-    ngx_http_server_name_t *first = (ngx_http_server_name_t *) one;
-    ngx_http_server_name_t *second = (ngx_http_server_name_t *) two;
-
-    return ngx_strcmp(first->name.data, second->name.data);
-}
-
-
 /*
  * add the server address, the server names and the server core module
  * configurations to the port (in_port)
  */
 
 static ngx_int_t
-ngx_http_add_address(ngx_conf_t *cf, ngx_http_in_port_t *in_port,
+ngx_http_add_address(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port,
     ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf)
 {
-    ngx_http_in_addr_t  *in_addr;
+    ngx_http_conf_in_addr_t  *in_addr;
 
     if (in_port->addrs.elts == NULL) {
-        if (ngx_array_init(&in_port->addrs, cf->pool, 4,
-                           sizeof(ngx_http_in_addr_t)) != NGX_OK)
+        if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4,
+                           sizeof(ngx_http_conf_in_addr_t)) != NGX_OK)
         {
             return NGX_ERROR;
         }
@@ -836,11 +862,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
     }
 
     in_addr->addr = lscf->addr;
+    in_addr->hash.buckets = NULL;
+    in_addr->hash.size = 0;
+    in_addr->dns_wildcards = NULL;
     in_addr->names.elts = NULL;
-    in_addr->hash = NULL;
-    in_addr->wildcards.elts = NULL;
     in_addr->core_srv_conf = cscf;
-    in_addr->conf = lscf->conf;
+    in_addr->default_server = lscf->conf.default_server;
+    in_addr->bind = lscf->conf.bind;
+    in_addr->listen_conf = &lscf->conf;
 
 #if (NGX_DEBUG)
     {
@@ -861,23 +890,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
  */
 
 static ngx_int_t
-ngx_http_add_names(ngx_conf_t *cf, ngx_http_in_addr_t *in_addr,
+ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr,
     ngx_http_core_srv_conf_t *cscf)
 {
     ngx_uint_t               i, n;
-    ngx_array_t             *array;
     ngx_http_server_name_t  *server_names, *name;
 
     if (in_addr->names.elts == NULL) {
-        if (ngx_array_init(&in_addr->names, cf->pool, 4,
-                           sizeof(ngx_http_server_name_t)) != NGX_OK)
-        {
-            return NGX_ERROR;
-        }
-    }
-
-    if (in_addr->wildcards.elts == NULL) {
-        if (ngx_array_init(&in_addr->wildcards, cf->pool, 1,
+        if (ngx_array_init(&in_addr->names, cf->temp_pool, 4,
                            sizeof(ngx_http_server_name_t)) != NGX_OK)
         {
             return NGX_ERROR;
@@ -895,17 +915,8 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                        "name: %V", &server_names[i].name);
 
-        /* TODO: duplicate names can be checked here */
 
-
-        if (server_names[i].wildcard) {
-            array = &in_addr->wildcards;
-
-        } else {
-            array = &in_addr->names;
-        }
-
-        name = ngx_array_push(array);
+        name = ngx_array_push(&in_addr->names);
         if (name == NULL) {
             return NGX_ERROR;
         }
@@ -926,7 +937,7 @@ ngx_http_merge_locations(ngx_conf_t *cf,
     ngx_uint_t                  i;
     ngx_http_core_loc_conf_t  **clcfp;
 
-    clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts;
+    clcfp = locations->elts;
 
     for (i = 0; i < locations->nelts; i++) {
         rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
@@ -944,3 +955,44 @@ ngx_http_merge_locations(ngx_conf_t *cf,
 
     return NGX_CONF_OK;
 }
+
+
+static int ngx_libc_cdecl
+ngx_http_cmp_conf_in_addrs(const void *one, const void *two)
+{
+    ngx_http_conf_in_addr_t  *first, *second;
+
+    first = (ngx_http_conf_in_addr_t *) one;
+    second = (ngx_http_conf_in_addr_t *) two;
+
+    if (first->addr == INADDR_ANY) {
+        /* the INADDR_ANY must be the last resort, shift it to the end */
+        return 1;
+    }
+
+    if (first->bind && !second->bind) {
+        /* shift explicit bind()ed addresses to the start */
+        return -1;
+    }
+
+    if (!first->bind && second->bind) {
+        /* shift explicit bind()ed addresses to the start */
+        return 1;
+    }
+
+    /* do not sort by default */
+
+    return 0;
+}
+
+
+static int ngx_libc_cdecl
+ngx_http_cmp_dns_wildcards(const void *one, const void *two)
+{
+    ngx_hash_key_t  *first, *second;
+
+    first = (ngx_hash_key_t *) one;
+    second = (ngx_hash_key_t *) two;
+
+    return ngx_strcmp(first->key.data, second->key.data);
+}