src/mail/ngx_mail.c - nginx-1.7.10

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_mail.h>


  9. static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  10. static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
  11.     ngx_mail_listen_t *listen);
  12. static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
  13. static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
  14.     ngx_mail_conf_addr_t *addr);
  15. #if (NGX_HAVE_INET6)
  16. static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
  17.     ngx_mail_conf_addr_t *addr);
  18. #endif
  19. static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);


  20. ngx_uint_t  ngx_mail_max_module;


  21. static ngx_command_t  ngx_mail_commands[] = {

  22.     { ngx_string("mail"),
  23.       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
  24.       ngx_mail_block,
  25.       0,
  26.       0,
  27.       NULL },

  28.     { ngx_string("imap"),
  29.       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
  30.       ngx_mail_block,
  31.       0,
  32.       0,
  33.       NULL },

  34.       ngx_null_command
  35. };


  36. static ngx_core_module_t  ngx_mail_module_ctx = {
  37.     ngx_string("mail"),
  38.     NULL,
  39.     NULL
  40. };


  41. ngx_module_t  ngx_mail_module = {
  42.     NGX_MODULE_V1,
  43.     &ngx_mail_module_ctx,                  /* module context */
  44.     ngx_mail_commands,                     /* module directives */
  45.     NGX_CORE_MODULE,                       /* module type */
  46.     NULL,                                  /* init master */
  47.     NULL,                                  /* init module */
  48.     NULL,                                  /* init process */
  49.     NULL,                                  /* init thread */
  50.     NULL,                                  /* exit thread */
  51.     NULL,                                  /* exit process */
  52.     NULL,                                  /* exit master */
  53.     NGX_MODULE_V1_PADDING
  54. };


  55. static char *
  56. ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  57. {
  58.     char                        *rv;
  59.     ngx_uint_t                   i, m, mi, s;
  60.     ngx_conf_t                   pcf;
  61.     ngx_array_t                  ports;
  62.     ngx_mail_listen_t           *listen;
  63.     ngx_mail_module_t           *module;
  64.     ngx_mail_conf_ctx_t         *ctx;
  65.     ngx_mail_core_srv_conf_t   **cscfp;
  66.     ngx_mail_core_main_conf_t   *cmcf;

  67.     if (cmd->name.data[0] == 'i') {
  68.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  69.                            "the \"imap\" directive is deprecated, "
  70.                            "use the \"mail\" directive instead");
  71.     }

  72.     /* the main mail context */

  73.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
  74.     if (ctx == NULL) {
  75.         return NGX_CONF_ERROR;
  76.     }

  77.     *(ngx_mail_conf_ctx_t **) conf = ctx;

  78.     /* count the number of the http modules and set up their indices */

  79.     ngx_mail_max_module = 0;
  80.     for (m = 0; ngx_modules[m]; m++) {
  81.         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  82.             continue;
  83.         }

  84.         ngx_modules[m]->ctx_index = ngx_mail_max_module++;
  85.     }


  86.     /* the mail main_conf context, it is the same in the all mail contexts */

  87.     ctx->main_conf = ngx_pcalloc(cf->pool,
  88.                                  sizeof(void *) * ngx_mail_max_module);
  89.     if (ctx->main_conf == NULL) {
  90.         return NGX_CONF_ERROR;
  91.     }


  92.     /*
  93.      * the mail null srv_conf context, it is used to merge
  94.      * the server{}s' srv_conf's
  95.      */

  96.     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
  97.     if (ctx->srv_conf == NULL) {
  98.         return NGX_CONF_ERROR;
  99.     }


  100.     /*
  101.      * create the main_conf's and the null srv_conf's of the all mail modules
  102.      */

  103.     for (m = 0; ngx_modules[m]; m++) {
  104.         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  105.             continue;
  106.         }

  107.         module = ngx_modules[m]->ctx;
  108.         mi = ngx_modules[m]->ctx_index;

  109.         if (module->create_main_conf) {
  110.             ctx->main_conf[mi] = module->create_main_conf(cf);
  111.             if (ctx->main_conf[mi] == NULL) {
  112.                 return NGX_CONF_ERROR;
  113.             }
  114.         }

  115.         if (module->create_srv_conf) {
  116.             ctx->srv_conf[mi] = module->create_srv_conf(cf);
  117.             if (ctx->srv_conf[mi] == NULL) {
  118.                 return NGX_CONF_ERROR;
  119.             }
  120.         }
  121.     }


  122.     /* parse inside the mail{} block */

  123.     pcf = *cf;
  124.     cf->ctx = ctx;

  125.     cf->module_type = NGX_MAIL_MODULE;
  126.     cf->cmd_type = NGX_MAIL_MAIN_CONF;
  127.     rv = ngx_conf_parse(cf, NULL);

  128.     if (rv != NGX_CONF_OK) {
  129.         *cf = pcf;
  130.         return rv;
  131.     }


  132.     /* init mail{} main_conf's, merge the server{}s' srv_conf's */

  133.     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
  134.     cscfp = cmcf->servers.elts;

  135.     for (m = 0; ngx_modules[m]; m++) {
  136.         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  137.             continue;
  138.         }

  139.         module = ngx_modules[m]->ctx;
  140.         mi = ngx_modules[m]->ctx_index;

  141.         /* init mail{} main_conf's */

  142.         cf->ctx = ctx;

  143.         if (module->init_main_conf) {
  144.             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
  145.             if (rv != NGX_CONF_OK) {
  146.                 *cf = pcf;
  147.                 return rv;
  148.             }
  149.         }

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

  151.             /* merge the server{}s' srv_conf's */

  152.             cf->ctx = cscfp[s]->ctx;

  153.             if (module->merge_srv_conf) {
  154.                 rv = module->merge_srv_conf(cf,
  155.                                             ctx->srv_conf[mi],
  156.                                             cscfp[s]->ctx->srv_conf[mi]);
  157.                 if (rv != NGX_CONF_OK) {
  158.                     *cf = pcf;
  159.                     return rv;
  160.                 }
  161.             }
  162.         }
  163.     }

  164.     *cf = pcf;


  165.     if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
  166.         != NGX_OK)
  167.     {
  168.         return NGX_CONF_ERROR;
  169.     }

  170.     listen = cmcf->listen.elts;

  171.     for (i = 0; i < cmcf->listen.nelts; i++) {
  172.         if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
  173.             return NGX_CONF_ERROR;
  174.         }
  175.     }

  176.     return ngx_mail_optimize_servers(cf, &ports);
  177. }


  178. static ngx_int_t
  179. ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
  180.     ngx_mail_listen_t *listen)
  181. {
  182.     in_port_t              p;
  183.     ngx_uint_t             i;
  184.     struct sockaddr       *sa;
  185.     struct sockaddr_in    *sin;
  186.     ngx_mail_conf_port_t  *port;
  187.     ngx_mail_conf_addr_t  *addr;
  188. #if (NGX_HAVE_INET6)
  189.     struct sockaddr_in6   *sin6;
  190. #endif

  191.     sa = (struct sockaddr *) &listen->sockaddr;

  192.     switch (sa->sa_family) {

  193. #if (NGX_HAVE_INET6)
  194.     case AF_INET6:
  195.         sin6 = (struct sockaddr_in6 *) sa;
  196.         p = sin6->sin6_port;
  197.         break;
  198. #endif

  199. #if (NGX_HAVE_UNIX_DOMAIN)
  200.     case AF_UNIX:
  201.         p = 0;
  202.         break;
  203. #endif

  204.     default: /* AF_INET */
  205.         sin = (struct sockaddr_in *) sa;
  206.         p = sin->sin_port;
  207.         break;
  208.     }

  209.     port = ports->elts;
  210.     for (i = 0; i < ports->nelts; i++) {
  211.         if (p == port[i].port && sa->sa_family == port[i].family) {

  212.             /* a port is already in the port list */

  213.             port = &port[i];
  214.             goto found;
  215.         }
  216.     }

  217.     /* add a port to the port list */

  218.     port = ngx_array_push(ports);
  219.     if (port == NULL) {
  220.         return NGX_ERROR;
  221.     }

  222.     port->family = sa->sa_family;
  223.     port->port = p;

  224.     if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
  225.                        sizeof(ngx_mail_conf_addr_t))
  226.         != NGX_OK)
  227.     {
  228.         return NGX_ERROR;
  229.     }

  230. found:

  231.     addr = ngx_array_push(&port->addrs);
  232.     if (addr == NULL) {
  233.         return NGX_ERROR;
  234.     }

  235.     addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
  236.     addr->socklen = listen->socklen;
  237.     addr->ctx = listen->ctx;
  238.     addr->bind = listen->bind;
  239.     addr->wildcard = listen->wildcard;
  240.     addr->so_keepalive = listen->so_keepalive;
  241. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  242.     addr->tcp_keepidle = listen->tcp_keepidle;
  243.     addr->tcp_keepintvl = listen->tcp_keepintvl;
  244.     addr->tcp_keepcnt = listen->tcp_keepcnt;
  245. #endif
  246. #if (NGX_MAIL_SSL)
  247.     addr->ssl = listen->ssl;
  248. #endif
  249. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  250.     addr->ipv6only = listen->ipv6only;
  251. #endif

  252.     return NGX_OK;
  253. }


  254. static char *
  255. ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
  256. {
  257.     ngx_uint_t             i, p, last, bind_wildcard;
  258.     ngx_listening_t       *ls;
  259.     ngx_mail_port_t       *mport;
  260.     ngx_mail_conf_port_t  *port;
  261.     ngx_mail_conf_addr_t  *addr;

  262.     port = ports->elts;
  263.     for (p = 0; p < ports->nelts; p++) {

  264.         ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
  265.                  sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs);

  266.         addr = port[p].addrs.elts;
  267.         last = port[p].addrs.nelts;

  268.         /*
  269.          * if there is the binding to the "*:port" then we need to bind()
  270.          * to the "*:port" only and ignore the other bindings
  271.          */

  272.         if (addr[last - 1].wildcard) {
  273.             addr[last - 1].bind = 1;
  274.             bind_wildcard = 1;

  275.         } else {
  276.             bind_wildcard = 0;
  277.         }

  278.         i = 0;

  279.         while (i < last) {

  280.             if (bind_wildcard && !addr[i].bind) {
  281.                 i++;
  282.                 continue;
  283.             }

  284.             ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
  285.             if (ls == NULL) {
  286.                 return NGX_CONF_ERROR;
  287.             }

  288.             ls->addr_ntop = 1;
  289.             ls->handler = ngx_mail_init_connection;
  290.             ls->pool_size = 256;

  291.             /* TODO: error_log directive */
  292.             ls->logp = &cf->cycle->new_log;
  293.             ls->log.data = &ls->addr_text;
  294.             ls->log.handler = ngx_accept_log_error;

  295.             ls->keepalive = addr[i].so_keepalive;
  296. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  297.             ls->keepidle = addr[i].tcp_keepidle;
  298.             ls->keepintvl = addr[i].tcp_keepintvl;
  299.             ls->keepcnt = addr[i].tcp_keepcnt;
  300. #endif

  301. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  302.             ls->ipv6only = addr[i].ipv6only;
  303. #endif

  304.             mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
  305.             if (mport == NULL) {
  306.                 return NGX_CONF_ERROR;
  307.             }

  308.             ls->servers = mport;

  309.             if (i == last - 1) {
  310.                 mport->naddrs = last;

  311.             } else {
  312.                 mport->naddrs = 1;
  313.                 i = 0;
  314.             }

  315.             switch (ls->sockaddr->sa_family) {
  316. #if (NGX_HAVE_INET6)
  317.             case AF_INET6:
  318.                 if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
  319.                     return NGX_CONF_ERROR;
  320.                 }
  321.                 break;
  322. #endif
  323.             default: /* AF_INET */
  324.                 if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
  325.                     return NGX_CONF_ERROR;
  326.                 }
  327.                 break;
  328.             }

  329.             addr++;
  330.             last--;
  331.         }
  332.     }

  333.     return NGX_CONF_OK;
  334. }


  335. static ngx_int_t
  336. ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
  337.     ngx_mail_conf_addr_t *addr)
  338. {
  339.     u_char              *p;
  340.     size_t               len;
  341.     ngx_uint_t           i;
  342.     ngx_mail_in_addr_t  *addrs;
  343.     struct sockaddr_in  *sin;
  344.     u_char               buf[NGX_SOCKADDR_STRLEN];

  345.     mport->addrs = ngx_pcalloc(cf->pool,
  346.                                mport->naddrs * sizeof(ngx_mail_in_addr_t));
  347.     if (mport->addrs == NULL) {
  348.         return NGX_ERROR;
  349.     }

  350.     addrs = mport->addrs;

  351.     for (i = 0; i < mport->naddrs; i++) {

  352.         sin = (struct sockaddr_in *) addr[i].sockaddr;
  353.         addrs[i].addr = sin->sin_addr.s_addr;

  354.         addrs[i].conf.ctx = addr[i].ctx;
  355. #if (NGX_MAIL_SSL)
  356.         addrs[i].conf.ssl = addr[i].ssl;
  357. #endif

  358.         len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
  359.                             NGX_SOCKADDR_STRLEN, 1);

  360.         p = ngx_pnalloc(cf->pool, len);
  361.         if (p == NULL) {
  362.             return NGX_ERROR;
  363.         }

  364.         ngx_memcpy(p, buf, len);

  365.         addrs[i].conf.addr_text.len = len;
  366.         addrs[i].conf.addr_text.data = p;
  367.     }

  368.     return NGX_OK;
  369. }


  370. #if (NGX_HAVE_INET6)

  371. static ngx_int_t
  372. ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
  373.     ngx_mail_conf_addr_t *addr)
  374. {
  375.     u_char               *p;
  376.     size_t                len;
  377.     ngx_uint_t            i;
  378.     ngx_mail_in6_addr_t  *addrs6;
  379.     struct sockaddr_in6  *sin6;
  380.     u_char                buf[NGX_SOCKADDR_STRLEN];

  381.     mport->addrs = ngx_pcalloc(cf->pool,
  382.                                mport->naddrs * sizeof(ngx_mail_in6_addr_t));
  383.     if (mport->addrs == NULL) {
  384.         return NGX_ERROR;
  385.     }

  386.     addrs6 = mport->addrs;

  387.     for (i = 0; i < mport->naddrs; i++) {

  388.         sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
  389.         addrs6[i].addr6 = sin6->sin6_addr;

  390.         addrs6[i].conf.ctx = addr[i].ctx;
  391. #if (NGX_MAIL_SSL)
  392.         addrs6[i].conf.ssl = addr[i].ssl;
  393. #endif

  394.         len = ngx_sock_ntop(addr[i].sockaddr, addr[i].socklen, buf,
  395.                             NGX_SOCKADDR_STRLEN, 1);

  396.         p = ngx_pnalloc(cf->pool, len);
  397.         if (p == NULL) {
  398.             return NGX_ERROR;
  399.         }

  400.         ngx_memcpy(p, buf, len);

  401.         addrs6[i].conf.addr_text.len = len;
  402.         addrs6[i].conf.addr_text.data = p;
  403.     }

  404.     return NGX_OK;
  405. }

  406. #endif


  407. static ngx_int_t
  408. ngx_mail_cmp_conf_addrs(const void *one, const void *two)
  409. {
  410.     ngx_mail_conf_addr_t  *first, *second;

  411.     first = (ngx_mail_conf_addr_t *) one;
  412.     second = (ngx_mail_conf_addr_t *) two;

  413.     if (first->wildcard) {
  414.         /* a wildcard must be the last resort, shift it to the end */
  415.         return 1;
  416.     }

  417.     if (second->wildcard) {
  418.         /* a wildcard must be the last resort, shift it to the end */
  419.         return -1;
  420.     }

  421.     if (first->bind && !second->bind) {
  422.         /* shift explicit bind()ed addresses to the start */
  423.         return -1;
  424.     }

  425.     if (!first->bind && second->bind) {
  426.         /* shift explicit bind()ed addresses to the start */
  427.         return 1;
  428.     }

  429.     /* do not sort by default */

  430.     return 0;
  431. }