nginx模块开发—HTTP初始化之listen

1、知识百科

nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解。与网络有关的配置命令主要有两个:listensever_namelisten命令设置nginx监听地址,对于IP协议,这个地址就是addressport,对于UNIX域套接字协议,这个地址就是path,一条listen指令只能指定一个address或者portaddress也可以是主机名,比如:

listen 127.0.0.1:8000;

 listen 127.0.0.1;

listen 8000;

 listen *:8000;

 listen localhost:8000;

 listen [::]:8000;

 listen [fe80::1];

 listen unix:/var/run/nginx.sock;

server_name指令列出虚拟主机的所有主机名,如server_name example.com *.example.com www.example.*,用空格分割。

2、数据结构

clip_image002

clip_image002[4]

ngx_http_conf_port_tngx_http_core_listen入口)

typedef struct {

    ngx_int_t                  family;

    in_port_t                  port;

    ngx_array_t                addrs;     /* array of ngx_http_conf_addr_t */

} ngx_http_conf_port_t;

ngx_http_conf_addr_t

typedef struct {

    ngx_http_listen_opt_t      opt;

    ngx_hash_t                 hash;

    ngx_hash_wildcard_t       *wc_head;

    ngx_hash_wildcard_t       *wc_tail;

 

    ngx_http_core_srv_conf_t  *default_server;

    ngx_array_t                servers;  /* array of ngx_http_core_srv_conf_t */

} ngx_http_conf_addr_t;

ngx_http_core_srv_conf_t

typedef struct {

    /* array of the ngx_http_server_name_t, "server_name" directive */

    ngx_array_t                 server_names;

 

    /* server ctx */

    ngx_http_conf_ctx_t        *ctx;

 

    ngx_str_t                   server_name;

 

    size_t                      connection_pool_size;

    size_t                      request_pool_size;

    size_t                      client_header_buffer_size;

 

    ngx_bufs_t                  large_client_header_buffers;

 

    ngx_msec_t                  client_header_timeout;

 

    ngx_flag_t                  ignore_invalid_headers;

    ngx_flag_t                  merge_slashes;

    ngx_flag_t                  underscores_in_headers;

 

    unsigned                    listen:1;

 

    ngx_http_core_loc_conf_t  **named_locations;

} ngx_http_core_srv_conf_t;

ngx_http_listen_opt_t(重要)

typedef struct {

    union {

        struct sockaddr        sockaddr;

        struct sockaddr_in     sockaddr_in;

        u_char              sockaddr_data[NGX_SOCKADDRLEN];

    } u;

 

    socklen_t                  socklen;

 

    unsigned                   set:1;                       // bind/backlog/…

    unsigned                   default_server:1;  // default_server

    unsigned                   bind:1;                    // bind/backlog/…

    unsigned                   wildcard:1;

#if (NGX_HTTP_SSL)

    unsigned                   ssl:1;

#endif

#if (NGX_HTTP_SPDY)

    unsigned                   spdy:1;                  // spdy

#endif

    unsigned                   so_keepalive:2;

    unsigned                   proxy_protocol:1;   // proxy_protocol

 

    int                        backlog;   // backlog

    int                        rcvbuf;    // rcvbuf

    int                        sndbuf;    // sndbuf

    。。。

 

    u_char                     addr[NGX_SOCKADDR_STRLEN + 1];  // 0.0.0.0:8000

} ngx_http_listen_opt_t;

ngx_listening_sngx_http_init_connection入口)

image

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;

 

    ngx_connection_handler_pt   handler;

 

    void               *servers;  /* array of ngx_http_port_t, for example */

    。。。

    ngx_listening_t    *previous;

    ngx_connection_t   *connection;

 

    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            keepalive:2;

 

};

ngx_http_port_t

typedef struct {

    /* ngx_http_in_addr_t or ngx_http_in6_addr_t */

    void                      *addrs;

    ngx_uint_t                 naddrs;

} ngx_http_port_t;

ngx_http_in_addr_t

typedef struct {

    in_addr_t                  addr;

    ngx_http_addr_conf_t       conf;

} ngx_http_in_addr_t;

ngx_http_addr_conf_s

struct ngx_http_addr_conf_s {

    /* the default server configuration for this address:port */

    ngx_http_core_srv_conf_t  *default_server;

 

    ngx_http_virtual_names_t  *virtual_names;

 

#if (NGX_HTTP_SSL)

    unsigned                   ssl:1;

#endif

#if (NGX_HTTP_SPDY)

    unsigned                   spdy:1;

#endif

    unsigned                   proxy_protocol:1;

};

3、源码解析

clip_image002[6]

ngx_http_core_server_name

函数功能:解析server_name指令。

static char *

ngx_http_core_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

    ngx_http_core_srv_conf_t *cscf = conf;

 

    u_char                   ch;

    ngx_str_t               *value;

    ngx_uint_t               i;

    ngx_http_server_name_t  *sn;

 

    value = cf->args->elts;

 

    for (i = 1; i < cf->args->nelts; i++) {

 

        ch = value[i].data[0];

 

        if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.'))

            || (ch == '.' && value[i].len < 2))

        {

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                               "server name \"%V\" is invalid", &value[i]);

            return NGX_CONF_ERROR;

        }

 

        if (ngx_strchr(value[i].data, '/')) {

            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,

                               "server name \"%V\" has suspicious symbols",

                               &value[i]);

        }

 

        sn = ngx_array_push(&cscf->server_names);

        if (sn == NULL) {

            return NGX_CONF_ERROR;

        }

        sn->server = cscf;

 

        if (ngx_strcasecmp(value[i].data, (u_char *) "$hostname") == 0) {

            sn->name = cf->cycle->hostname;

        } else {

            sn->name = value[i];

        }

 

        if (value[i].data[0] != '~') {

            ngx_strlow(sn->name.data, sn->name.data, sn->name.len);

            continue;

        }

。。。

    }

 

    return NGX_CONF_OK;

}

ngx_http_core_listen

函数功能:解析listen指令。

static char *

ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)

{

    ngx_http_core_srv_conf_t *cscf = conf;

 

    ngx_str_t              *value, size;

    ngx_url_t               u;

    ngx_uint_t              n;

    ngx_http_listen_opt_t   lsopt;

 

    cscf->listen = 1;

 

    value = cf->args->elts;

 

    ngx_memzero(&u, sizeof(ngx_url_t));

 

    u.url = value[1];

    u.listen = 1;

u.default_port = 80;

 

    //解析listen命令后面的参数,ip:port

    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {

        if (u.err) {

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                               "%s in \"%V\" of the \"listen\" directive",

                               u.err, &u.url);

        }

 

        return NGX_CONF_ERROR;

    }

 

    ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));

    ngx_memcpy(&lsopt.u.sockaddr, u.sockaddr, u.socklen);

 

    lsopt.socklen = u.socklen;

    lsopt.backlog = NGX_LISTEN_BACKLOG;

    lsopt.rcvbuf = -1;

    lsopt.sndbuf = -1;

    lsopt.wildcard = u.wildcard;   //listen 80

 

    (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.socklen, lsopt.addr,

                         NGX_SOCKADDR_STRLEN, 1);

 

    for (n = 2; n < cf->args->nelts; n++) {

 

        if (ngx_strcmp(value[n].data, "default_server") == 0

            || ngx_strcmp(value[n].data, "default") == 0)

        {

            lsopt.default_server = 1;

            continue;

        }

        ….

        if (ngx_strncmp(value[n].data, "backlog=", 8) == 0) {

            lsopt.backlog = ngx_atoi(value[n].data + 8, value[n].len - 8);

            lsopt.set = 1;

            lsopt.bind = 1;

 

            if (lsopt.backlog == NGX_ERROR || lsopt.backlog == 0) {

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                                   "invalid backlog \"%V\"", &value[n]);

                return NGX_CONF_ERROR;

            }

 

            continue;

        }

 

        if (ngx_strcmp(value[n].data, "ssl") == 0) {

#if (NGX_HTTP_SSL)

            lsopt.ssl = 1;

            continue;

#else

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                               "the \"ssl\" parameter requires "

                               "ngx_http_ssl_module");

            return NGX_CONF_ERROR;

#endif

        }

 

        if (ngx_strcmp(value[n].data, "spdy") == 0) {

#if (NGX_HTTP_SPDY)

            lsopt.spdy = 1;

            continue;

#else

            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                               "the \"spdy\" parameter requires "

                               "ngx_http_spdy_module");

            return NGX_CONF_ERROR;

#endif

        }

        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                           "invalid parameter \"%V\"", &value[n]);

        return NGX_CONF_ERROR;

}

 

    //将解析到的虚拟主机的地址信息加入到监听列表中

    if (ngx_http_add_listen(cf, cscf, &lsopt) == NGX_OK) {

        return NGX_CONF_OK;

    }

 

    return NGX_CONF_ERROR;

}

ngx_http_add_listen

函数功能:以port为粒度,添加addr(即1.1.1.1:80、2.2.2.2:80和80,会放在相同的cmcf->port[i]中)。

clip_image002[8]

ngx_int_t

ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_listen_opt_t *lsopt)

{

    in_port_t                   p;

    ngx_uint_t                  i;

    struct sockaddr            *sa;

    struct sockaddr_in         *sin;

    ngx_http_conf_port_t       *port;

    ngx_http_core_main_conf_t  *cmcf;

 

    cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

 

    if (cmcf->ports == NULL) {   //全局

        cmcf->ports = ngx_array_create(cf->temp_pool, 2,

                                       sizeof(ngx_http_conf_port_t));

        if (cmcf->ports == NULL) {

            return NGX_ERROR;

        }

    }

 

    sa = &lsopt->u.sockaddr;

 

    switch (sa->sa_family) {

 

    default: /* AF_INET */

        sin = &lsopt->u.sockaddr_in;

        p = sin->sin_port;

        break;

    }

 

    port = cmcf->ports->elts;

    for (i = 0; i < cmcf->ports->nelts; i++) {

 

        if (p != port[i].port || sa->sa_family != port[i].family) {

            continue;

        }

 

        //相同的port共用相同的address

        return ngx_http_add_addresses(cf, cscf, &port[i], lsopt);

    }

 

    port = ngx_array_push(cmcf->ports);

    if (port == NULL) {

        return NGX_ERROR;

    }

 

    port->family = sa->sa_family;

    port->port = p;

    port->addrs.elts = NULL;

 

    return ngx_http_add_address(cf, cscf, port, lsopt);

}

ngx_http_add_addresses

函数功能:相同的port,相同的addr,则ngx_http_add_server(如listen 8080,server_name hello和server_name world),相同的port,不同的addr,则ngx_http_add_address(如listen 1.1.1.1:80和2.2.2.2:80)。

clip_image002[10]

 

nginx模块开发(42)—网络初始化之listen(上) - cjhust - 我一直在努力

static ngx_int_t

ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)

{

    u_char                *p;

    size_t                 len, off;

    ngx_uint_t             i, default_server;

    struct sockaddr       *sa;

    ngx_http_conf_addr_t  *addr;

#if (NGX_HTTP_SSL)

    ngx_uint_t             ssl;

#endif

#if (NGX_HTTP_SPDY)

    ngx_uint_t             spdy;

#endif

 

    sa = &lsopt->u.sockaddr;

 

    switch (sa->sa_family) {

 

    default: /* AF_INET */

        off = offsetof(struct sockaddr_in, sin_addr);  // 4

        len = 4;

        break;

    }

 

    p = lsopt->u.sockaddr_data + off;  //u_char

 

    addr = port->addrs.elts;

 

    for (i = 0; i < port->addrs.nelts; i++) {

 

        if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) {   //比较sin_addr

            continue;

        }

 

        //相同的addr:port,不同的server_name

        if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {

            return NGX_ERROR;

        }

 

        /* preserve default_server bit during listen options overwriting */

        default_server = addr[i].opt.default_server;

 

#if (NGX_HTTP_SSL)

        ssl = lsopt->ssl || addr[i].opt.ssl;

#endif

#if (NGX_HTTP_SPDY)

        spdy = lsopt->spdy || addr[i].opt.spdy;

#endif

 

        if (lsopt->set) {

 

            if (addr[i].opt.set) {

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                        "duplicate listen options for %s", addr[i].opt.addr);

                return NGX_ERROR;

            }

 

            addr[i].opt = *lsopt;

        }

 

        /* check the duplicate "default" server for this address:port */

        if (lsopt->default_server) {

 

            if (default_server) {

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                        "a duplicate default server for %s", addr[i].opt.addr);

                return NGX_ERROR;

            }

 

            default_server = 1;

            addr[i].default_server = cscf;

        }

 

        addr[i].opt.default_server = default_server;

#if (NGX_HTTP_SSL)

        addr[i].opt.ssl = ssl;

#endif

#if (NGX_HTTP_SPDY)

        addr[i].opt.spdy = spdy;

#endif

 

        return NGX_OK;

    }

 

    /* add the address to the addresses list that bound to this port */

    return ngx_http_add_address(cf, cscf, port, lsopt);

}

ngx_http_add_address

static ngx_int_t

ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)

{

    ngx_http_conf_addr_t  *addr;

 

    if (port->addrs.elts == NULL) {

        if (ngx_array_init(&port->addrs, cf->temp_pool, 4,

                           sizeof(ngx_http_conf_addr_t))

            != NGX_OK)

        {

            return NGX_ERROR;

        }

    }

 

    addr = ngx_array_push(&port->addrs);

    if (addr == NULL) {

        return NGX_ERROR;

    }

 

    addr->opt = *lsopt;

    addr->hash.buckets = NULL;

    addr->hash.size = 0;

    addr->wc_head = NULL;

    addr->wc_tail = NULL;

#if (NGX_PCRE)

    addr->nregex = 0;

    addr->regex = NULL;

#endif

    addr->default_server = cscf;

    addr->servers.elts = NULL;

 

    return ngx_http_add_server(cf, cscf, addr);

}

ngx_http_add_server

函数功能:将新的虚拟主机信息加入到这个地址的虚拟主机列表中。

static ngx_int_t

ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,

    ngx_http_conf_addr_t *addr)

{

    ngx_uint_t                  i;

    ngx_http_core_srv_conf_t  **server;

 

    if (addr->servers.elts == NULL) {

        if (ngx_array_init(&addr->servers, cf->temp_pool, 4,

                           sizeof(ngx_http_core_srv_conf_t *))

            != NGX_OK)

        {

            return NGX_ERROR;

        }

 

    } else {

        server = addr->servers.elts;

        for (i = 0; i < addr->servers.nelts; i++) {  //相同的server,相同的listen

            if (server[i] == cscf) {

                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,

                                   "a duplicate listen %s", addr->opt.addr);

                return NGX_ERROR;

            }

        }

    }

 

    server = ngx_array_push(&addr->servers);

    if (server == NULL) {

        return NGX_ERROR;

    }

 

    *server = cscf;

 

    return NGX_OK;

}

ngx_http_block->ngx_http_optimize_servers

image

函数功能:ngx_http_block的最后一步。

static ngx_int_t

ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,

    ngx_array_t *ports)

{

    ngx_uint_t             p, a;

    ngx_http_conf_port_t  *port;

    ngx_http_conf_addr_t  *addr;

 

    if (ports == NULL) {

        return NGX_OK;

    }

 

    port = ports->elts;

    for (p = 0; p < ports->nelts; p++) {

        //比如listen 80listen 127.0.0.1:80

        //排序原则:通配符如listen 80listen*:80,会排在最后面,listen 1.1.1.1:80 backlog=512等会排在最前面

        ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,

                 sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs);

 

        addr = port[p].addrs.elts;

        for (a = 0; a < port[p].addrs.nelts; a++) {

 

            if (addr[a].servers.nelts > 1   //相同的addr:port,不同的server_name

#if (NGX_PCRE)

                || addr[a].default_server->captures

#endif

               )

            {

                if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) {

                    return NGX_ERROR;

                }

            }

        }

 

        if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) {  //一个port,一个listening

            return NGX_ERROR;

        }

    }

 

    return NGX_OK;

}

ngx_http_server_names

函数功能:相同的addr:port的优化处理。

static ngx_int_t

ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,

    ngx_http_conf_addr_t *addr)

{

    ngx_int_t                   rc;

    ngx_uint_t                  n, s;

    ngx_hash_init_t             hash;

    ngx_hash_keys_arrays_t      ha;

    ngx_http_server_name_t     *name;

    ngx_http_core_srv_conf_t  **cscfp;

 

    ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t));

 

    ha.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);

    if (ha.temp_pool == NULL) {

        return NGX_ERROR;

    }

 

    ha.pool = cf->pool;

 

    if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {

        goto failed;

    }

 

    cscfp = addr->servers.elts;

 

    for (s = 0; s < addr->servers.nelts; s++) {

 

        name = cscfp[s]->server_names.elts;   //一个server可以有多个server_name

 

        for (n = 0; n < cscfp[s]->server_names.nelts; n++) {

 

            rc = ngx_hash_add_key(&ha, &name[n].name, name[n].server,

                                  NGX_HASH_WILDCARD_KEY);

 

            if (rc == NGX_ERROR) {

                return NGX_ERROR;

            }

 

            if (rc == NGX_DECLINED) {

                ngx_log_error(NGX_LOG_EMERG, cf->log, 0,

                              "invalid server name or wildcard \"%V\" on %s",

                              &name[n].name, addr->opt.addr);

                return NGX_ERROR;

            }

 

            if (rc == NGX_BUSY) {

                ngx_log_error(NGX_LOG_WARN, cf->log, 0,

                              "conflicting server name \"%V\" on %s, ignored",

                              &name[n].name, addr->opt.addr);

            }

        }

    }

 

    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;

 

    if (ha.keys.nelts) {   //无通配

        hash.hash = &addr->hash;

        hash.temp_pool = NULL;

 

        if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) {

            goto failed;

        }

    }

 

    if (ha.dns_wc_head.nelts) {  //前缀通配

 

        ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.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_wc_head.elts,

                                   ha.dns_wc_head.nelts)

            != NGX_OK)

        {

            goto failed;

        }

 

        addr->wc_head = (ngx_hash_wildcard_t *) hash.hash;

    }

 

    if (ha.dns_wc_tail.nelts) {  //后缀通配

 

        ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.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_wc_tail.elts,

                                   ha.dns_wc_tail.nelts)

            != NGX_OK)

        {

            goto failed;

        }

 

        addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash;

    }

 

    ngx_destroy_pool(ha.temp_pool);

 

    return NGX_OK;

 

failed:

 

    ngx_destroy_pool(ha.temp_pool);

 

    return NGX_ERROR;

}

 

ngx_http_cmp_conf_addrs

static ngx_int_t

ngx_http_cmp_conf_addrs(const void *one, const void *two)

{

    ngx_http_conf_addr_t  *first, *second;

 

    first = (ngx_http_conf_addr_t *) one;

    second = (ngx_http_conf_addr_t *) two;

 

    //通配符必须是最后一个,返回1,则表示要交换顺序

    if (first->opt.wildcard) {

        /* a wildcard address must be the last resort, shift it to the end */

        return 1;

    }

 

     //通配符必须是最后一个,不需要换位置

    if (second->opt.wildcard) {

        /* a wildcard address must be the last resort, shift it to the end */

        return -1;

    }

   

   //设置如backlog的,需要放在前面

    if (first->opt.bind && !second->opt.bind) {

        /* shift explicit bind()ed addresses to the start */

        return -1;

}

 

    //设置如backlog的,需要放在前面

    if (!first->opt.bind && second->opt.bind) {

        /* shift explicit bind()ed addresses to the start */

        return 1;

    }

 

    /* do not sort by default */

    return 0;

}

ngx_http_init_listening(重要)

clip_image002[14]

函数功能:用新的结构(cycle-> listening)存储这些关系。

static ngx_int_t

ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)

{

    ngx_uint_t                 i, last, bind_wildcard;

    ngx_listening_t           *ls;

    ngx_http_port_t           *hport;

    ngx_http_conf_addr_t      *addr;

 

    addr = port->addrs.elts;

    last = port->addrs.nelts;      //相同的port,不同的addr个数

 

    if (addr[last - 1].opt.wildcard) { //通配符需要放在最后一个,设置backlog的需要放在前面

        addr[last - 1].opt.bind = 1;

        bind_wildcard = 1;

    } else {

        bind_wildcard = 0;

    }

 

    i = 0;

 

    while (i < last) {

        if (bind_wildcard && !addr[i].opt.bind) {

            i++;

            continue;

        }

 

        //这个函数里面将会创建,并且初始化listen结构,这个listen已经存放在cycle结构的listen数组中

        ls = ngx_http_add_listening(cf, &addr[i]);    //port->addrs.elts

        if (ls == NULL) {

            return NGX_ERROR;

        }

 

        hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t));

        if (hport == NULL) {

            return NGX_ERROR;

        }

 

        ls->servers = hport;

 

        if (i == last - 1) {

            hport->naddrs = last;  //*:port和没有显式bindaddress:port放在同一个listen中,如listen 80listen 1.1.1.1:80可以放在一个listening

        } else {

            hport->naddrs = 1;

//重新赋值为0,因为最前面可能是listen 2.2.2.2:80 backlog=512这样的

            i = 0;                  

}

 

        switch (ls->sockaddr->sa_family) {

 

        default: /* AF_INET */

            if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) {

                return NGX_ERROR;

            }

            break;

        }

 

        addr++;

        last--;

    }

 

    return NGX_OK;

}



ngx_http_add_listening

static ngx_listening_t *

ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)

{

    ngx_listening_t           *ls;

    ngx_http_core_loc_conf_t  *clcf;

    ngx_http_core_srv_conf_t  *cscf;

 

    ls = ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);

    if (ls == NULL) {

        return NULL;

    }

 

    ls->addr_ntop = 1;

 

    ls->handler = ngx_http_init_connection;

 

    cscf = addr->default_server;

    ls->pool_size = cscf->connection_pool_size;

    ls->post_accept_timeout = cscf->client_header_timeout;

 

    clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];

 

    ls->logp = clcf->error_log;

    ls->log.data = &ls->addr_text;

    ls->log.handler = ngx_accept_log_error;

 

    ls->backlog = addr->opt.backlog;

    ls->rcvbuf = addr->opt.rcvbuf;

    ls->sndbuf = addr->opt.sndbuf;

 

ls->keepalive = addr->opt.so_keepalive;

 

    return ls;

}

ngx_create_listening

ngx_listening_t *

ngx_create_listening(ngx_conf_t *cf, void *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) {

    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;  //511

    ls->rcvbuf = -1;

ls->sndbuf = -1;

 

    return ls;

}

ngx_http_add_addrs

static ngx_int_t

ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,

    ngx_http_conf_addr_t *addr)

{

    ngx_uint_t                 i;

    ngx_http_in_addr_t        *addrs;

    struct sockaddr_in        *sin;

    ngx_http_virtual_names_t  *vn;

 

    hport->addrs = ngx_pcalloc(cf->pool,

                               hport->naddrs * sizeof(ngx_http_in_addr_t));

    if (hport->addrs == NULL) {

        return NGX_ERROR;

    }

 

    addrs = hport->addrs;

 

    for (i = 0; i < hport->naddrs; i++) {

 

        sin = &addr[i].opt.u.sockaddr_in;

        addrs[i].addr = sin->sin_addr.s_addr;

 

        addrs[i].conf.default_server = addr[i].default_server;

#if (NGX_HTTP_SSL)

        addrs[i].conf.ssl = addr[i].opt.ssl;

#endif

#if (NGX_HTTP_SPDY)

        addrs[i].conf.spdy = addr[i].opt.spdy;

#endif

        addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;

 

        if (addr[i].hash.buckets == NULL

            && (addr[i].wc_head == NULL

                || addr[i].wc_head->hash.buckets == NULL)

            && (addr[i].wc_tail == NULL

                || addr[i].wc_tail->hash.buckets == NULL)

#if (NGX_PCRE)

            && addr[i].nregex == 0

#endif

            )

        {

            continue;

        }

 

        vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));

        if (vn == NULL) {

            return NGX_ERROR;

        }

 

        addrs[i].conf.virtual_names = vn;

 

        vn->names.hash = addr[i].hash;

        vn->names.wc_head = addr[i].wc_head;

        vn->names.wc_tail = addr[i].wc_tail;

#if (NGX_PCRE)

        vn->nregex = addr[i].nregex;

        vn->regex = addr[i].regex;

#endif

    }

 

    return NGX_OK;

}

ngx_init_cycle

    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 (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;        //remain=1时,old_cycle不需要close fd()

 

                    if (ls[i].backlog != nls[n].backlog) {

                        nls[n].listen = 1;   //backlog不同的时候,会在configure_listening_sockets中重新listen(fd, backlog)

                    }

                    break;

                }

            }

 

            if (nls[n].fd == (ngx_socket_t) -1) {

                nls[n].open = 1;

            }

        }

 

    } else {

        ls = cycle->listening.elts;

        for (i = 0; i < cycle->listening.nelts; i++) {

            ls[i].open = 1;

        }

    }

 

    if (ngx_open_listening_sockets(cycle) != NGX_OK) {

        goto failed;

}

 

….

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);

    }

}

ngx_open_listening_sockets

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) {     //inherited_sockets有关

                continue;

            }

 

            if (ls[i].fd != (ngx_socket_t) -1) {

                continue;

            }

 

            if (ls[i].inherited) {

                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_event_flags & NGX_USE_AIO_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;

                }

            }

 

 

            if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {

                err = ngx_socket_errno;

 

                if (err == NGX_EADDRINUSE && ngx_test_config) {

                    continue;

                }

 

                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;

                }

 

                failed = 1;

 

                continue;

            }

 

            //listen 80listen 1.1.1.1:80 共用一个listening,即共用一个backlog

            if (listen(s, ls[i].backlog) == -1) {

                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,

                              "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);

                }

 

                return NGX_ERROR;

            }

 

            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;

}

ngx_configure_listening_sockets

void

ngx_configure_listening_sockets(ngx_cycle_t *cycle)

{

    int                        value;

    ngx_uint_t                 i;

    ngx_listening_t           *ls;

 

    ls = cycle->listening.elts;

    for (i = 0; i < cycle->listening.nelts; i++) {

 

        ls[i].log = *ls[i].logp;

 

        。。。

        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 (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);

            }

        }

    }

 

    return;

}

ngx_http_init_connection

函数功能:ngx_event_accept后的ls->handler= ngx_http_init_connection

void

ngx_http_init_connection(ngx_connection_t *c)

{

    ngx_uint_t              i;

    ngx_event_t            *rev;

    struct sockaddr_in     *sin;

    ngx_http_port_t        *port;

    ngx_http_in_addr_t     *addr;

    ngx_http_log_ctx_t     *ctx;

    ngx_http_connection_t  *hc;

 

    hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t));

    if (hc == NULL) {

        ngx_http_close_connection(c);

        return;

    }

 

    c->data = hc;

 

    /* find the server configuration for the address:port */

 

    port = c->listening->servers;   /*ngx_http_port_t */

    if (port->naddrs > 1) {

 

        if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {

            ngx_http_close_connection(c);

            return;

        }

 

        switch (c->local_sockaddr->sa_family) {

        default: /* AF_INET */

            sin = (struct sockaddr_in *) c->local_sockaddr;  //here

 

            addr = port->addrs;

 

            for (i = 0; i < port->naddrs - 1; i++) {

                if (addr[i].addr == sin->sin_addr.s_addr) {

                    break;

                }

            }

 

            hc->addr_conf = &addr[i].conf;

 

            break;

        }

 

    } else {

 

        switch (c->local_sockaddr->sa_family) {

        default: /* AF_INET */

            addr = port->addrs;

            hc->addr_conf = &addr[0].conf;

            break;

        }

    }

 

    

 

    rev = c->read;

    rev->handler = ngx_http_wait_request_handler;   //普通request_handler

    c->write->handler = ngx_http_empty_handler;

 

#if (NGX_HTTP_SPDY)

    if (hc->addr_conf->spdy) {

        rev->handler = ngx_http_spdy_init;         //spdy request_handler

    }

#endif

 

 

    if (rev->ready) {

        /* the deferred accept(), rtsig, aio, iocp */

 

        if (ngx_use_accept_mutex) {

            ngx_post_event(rev, &ngx_posted_events);

            return;

        }

 

        rev->handler(rev);

        return;

    }

 

    ngx_add_timer(rev, c->listening->post_accept_timeout);

    ngx_reusable_connection(c, 1);

 

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {

        ngx_http_close_connection(c);

        return;

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值