src/mail/ngx_mail_core_module.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 void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
  10. static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
  11. static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
  12.     void *child);
  13. static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
  14.     void *conf);
  15. static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
  16.     void *conf);
  17. static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
  18.     void *conf);
  19. static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
  20.     void *conf);


  21. static ngx_conf_deprecated_t  ngx_conf_deprecated_so_keepalive = {
  22.     ngx_conf_deprecated, "so_keepalive",
  23.     "so_keepalive\" parameter of the \"listen"
  24. };


  25. static ngx_command_t  ngx_mail_core_commands[] = {

  26.     { ngx_string("server"),
  27.       NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
  28.       ngx_mail_core_server,
  29.       0,
  30.       0,
  31.       NULL },

  32.     { ngx_string("listen"),
  33.       NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
  34.       ngx_mail_core_listen,
  35.       NGX_MAIL_SRV_CONF_OFFSET,
  36.       0,
  37.       NULL },

  38.     { ngx_string("protocol"),
  39.       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  40.       ngx_mail_core_protocol,
  41.       NGX_MAIL_SRV_CONF_OFFSET,
  42.       0,
  43.       NULL },

  44.     { ngx_string("so_keepalive"),
  45.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
  46.       ngx_conf_set_flag_slot,
  47.       NGX_MAIL_SRV_CONF_OFFSET,
  48.       offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
  49.       &ngx_conf_deprecated_so_keepalive },

  50.     { ngx_string("timeout"),
  51.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  52.       ngx_conf_set_msec_slot,
  53.       NGX_MAIL_SRV_CONF_OFFSET,
  54.       offsetof(ngx_mail_core_srv_conf_t, timeout),
  55.       NULL },

  56.     { ngx_string("server_name"),
  57.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  58.       ngx_conf_set_str_slot,
  59.       NGX_MAIL_SRV_CONF_OFFSET,
  60.       offsetof(ngx_mail_core_srv_conf_t, server_name),
  61.       NULL },

  62.     { ngx_string("resolver"),
  63.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
  64.       ngx_mail_core_resolver,
  65.       NGX_MAIL_SRV_CONF_OFFSET,
  66.       0,
  67.       NULL },

  68.     { ngx_string("resolver_timeout"),
  69.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  70.       ngx_conf_set_msec_slot,
  71.       NGX_MAIL_SRV_CONF_OFFSET,
  72.       offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
  73.       NULL },

  74.       ngx_null_command
  75. };


  76. static ngx_mail_module_t  ngx_mail_core_module_ctx = {
  77.     NULL,                                  /* protocol */

  78.     ngx_mail_core_create_main_conf,        /* create main configuration */
  79.     NULL,                                  /* init main configuration */

  80.     ngx_mail_core_create_srv_conf,         /* create server configuration */
  81.     ngx_mail_core_merge_srv_conf           /* merge server configuration */
  82. };


  83. ngx_module_t  ngx_mail_core_module = {
  84.     NGX_MODULE_V1,
  85.     &ngx_mail_core_module_ctx,             /* module context */
  86.     ngx_mail_core_commands,                /* module directives */
  87.     NGX_MAIL_MODULE,                       /* module type */
  88.     NULL,                                  /* init master */
  89.     NULL,                                  /* init module */
  90.     NULL,                                  /* init process */
  91.     NULL,                                  /* init thread */
  92.     NULL,                                  /* exit thread */
  93.     NULL,                                  /* exit process */
  94.     NULL,                                  /* exit master */
  95.     NGX_MODULE_V1_PADDING
  96. };


  97. static void *
  98. ngx_mail_core_create_main_conf(ngx_conf_t *cf)
  99. {
  100.     ngx_mail_core_main_conf_t  *cmcf;

  101.     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
  102.     if (cmcf == NULL) {
  103.         return NULL;
  104.     }

  105.     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
  106.                        sizeof(ngx_mail_core_srv_conf_t *))
  107.         != NGX_OK)
  108.     {
  109.         return NULL;
  110.     }

  111.     if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
  112.         != NGX_OK)
  113.     {
  114.         return NULL;
  115.     }

  116.     return cmcf;
  117. }


  118. static void *
  119. ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
  120. {
  121.     ngx_mail_core_srv_conf_t  *cscf;

  122.     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
  123.     if (cscf == NULL) {
  124.         return NULL;
  125.     }

  126.     /*
  127.      * set by ngx_pcalloc():
  128.      *
  129.      *     cscf->protocol = NULL;
  130.      */

  131.     cscf->timeout = NGX_CONF_UNSET_MSEC;
  132.     cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
  133.     cscf->so_keepalive = NGX_CONF_UNSET;

  134.     cscf->resolver = NGX_CONF_UNSET_PTR;

  135.     cscf->file_name = cf->conf_file->file.name.data;
  136.     cscf->line = cf->conf_file->line;

  137.     return cscf;
  138. }


  139. static char *
  140. ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  141. {
  142.     ngx_mail_core_srv_conf_t *prev = parent;
  143.     ngx_mail_core_srv_conf_t *conf = child;

  144.     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
  145.     ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
  146.                               30000);

  147.     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);


  148.     ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");

  149.     if (conf->server_name.len == 0) {
  150.         conf->server_name = cf->cycle->hostname;
  151.     }

  152.     if (conf->protocol == NULL) {
  153.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  154.                       "unknown mail protocol for server in %s:%ui",
  155.                       conf->file_name, conf->line);
  156.         return NGX_CONF_ERROR;
  157.     }

  158.     ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);

  159.     return NGX_CONF_OK;
  160. }


  161. static char *
  162. ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  163. {
  164.     char                       *rv;
  165.     void                       *mconf;
  166.     ngx_uint_t                  m;
  167.     ngx_conf_t                  pcf;
  168.     ngx_mail_module_t          *module;
  169.     ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
  170.     ngx_mail_core_srv_conf_t   *cscf, **cscfp;
  171.     ngx_mail_core_main_conf_t  *cmcf;

  172.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
  173.     if (ctx == NULL) {
  174.         return NGX_CONF_ERROR;
  175.     }

  176.     mail_ctx = cf->ctx;
  177.     ctx->main_conf = mail_ctx->main_conf;

  178.     /* the server{}'s srv_conf */

  179.     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
  180.     if (ctx->srv_conf == NULL) {
  181.         return NGX_CONF_ERROR;
  182.     }

  183.     for (m = 0; ngx_modules[m]; m++) {
  184.         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  185.             continue;
  186.         }

  187.         module = ngx_modules[m]->ctx;

  188.         if (module->create_srv_conf) {
  189.             mconf = module->create_srv_conf(cf);
  190.             if (mconf == NULL) {
  191.                 return NGX_CONF_ERROR;
  192.             }

  193.             ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
  194.         }
  195.     }

  196.     /* the server configuration context */

  197.     cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
  198.     cscf->ctx = ctx;

  199.     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];

  200.     cscfp = ngx_array_push(&cmcf->servers);
  201.     if (cscfp == NULL) {
  202.         return NGX_CONF_ERROR;
  203.     }

  204.     *cscfp = cscf;


  205.     /* parse inside server{} */

  206.     pcf = *cf;
  207.     cf->ctx = ctx;
  208.     cf->cmd_type = NGX_MAIL_SRV_CONF;

  209.     rv = ngx_conf_parse(cf, NULL);

  210.     *cf = pcf;

  211.     return rv;
  212. }


  213. static char *
  214. ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  215. {
  216.     ngx_mail_core_srv_conf_t  *cscf = conf;

  217.     size_t                      len, off;
  218.     in_port_t                   port;
  219.     ngx_str_t                  *value;
  220.     ngx_url_t                   u;
  221.     ngx_uint_t                  i, m;
  222.     struct sockaddr            *sa;
  223.     ngx_mail_listen_t          *ls;
  224.     ngx_mail_module_t          *module;
  225.     struct sockaddr_in         *sin;
  226.     ngx_mail_core_main_conf_t  *cmcf;
  227. #if (NGX_HAVE_INET6)
  228.     struct sockaddr_in6        *sin6;
  229. #endif

  230.     value = cf->args->elts;

  231.     ngx_memzero(&u, sizeof(ngx_url_t));

  232.     u.url = value[1];
  233.     u.listen = 1;

  234.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  235.         if (u.err) {
  236.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  237.                                "%s in \"%V\" of the \"listen\" directive",
  238.                                u.err, &u.url);
  239.         }

  240.         return NGX_CONF_ERROR;
  241.     }

  242.     cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);

  243.     ls = cmcf->listen.elts;

  244.     for (i = 0; i < cmcf->listen.nelts; i++) {

  245.         sa = (struct sockaddr *) ls[i].sockaddr;

  246.         if (sa->sa_family != u.family) {
  247.             continue;
  248.         }

  249.         switch (sa->sa_family) {

  250. #if (NGX_HAVE_INET6)
  251.         case AF_INET6:
  252.             off = offsetof(struct sockaddr_in6, sin6_addr);
  253.             len = 16;
  254.             sin6 = (struct sockaddr_in6 *) sa;
  255.             port = sin6->sin6_port;
  256.             break;
  257. #endif

  258. #if (NGX_HAVE_UNIX_DOMAIN)
  259.         case AF_UNIX:
  260.             off = offsetof(struct sockaddr_un, sun_path);
  261.             len = sizeof(((struct sockaddr_un *) sa)->sun_path);
  262.             port = 0;
  263.             break;
  264. #endif

  265.         default: /* AF_INET */
  266.             off = offsetof(struct sockaddr_in, sin_addr);
  267.             len = 4;
  268.             sin = (struct sockaddr_in *) sa;
  269.             port = sin->sin_port;
  270.             break;
  271.         }

  272.         if (ngx_memcmp(ls[i].sockaddr + off, u.sockaddr + off, len) != 0) {
  273.             continue;
  274.         }

  275.         if (port != u.port) {
  276.             continue;
  277.         }

  278.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  279.                            "duplicate \"%V\" address and port pair", &u.url);
  280.         return NGX_CONF_ERROR;
  281.     }

  282.     ls = ngx_array_push(&cmcf->listen);
  283.     if (ls == NULL) {
  284.         return NGX_CONF_ERROR;
  285.     }

  286.     ngx_memzero(ls, sizeof(ngx_mail_listen_t));

  287.     ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen);

  288.     ls->socklen = u.socklen;
  289.     ls->wildcard = u.wildcard;
  290.     ls->ctx = cf->ctx;

  291. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  292.     ls->ipv6only = 1;
  293. #endif

  294.     if (cscf->protocol == NULL) {
  295.         for (m = 0; ngx_modules[m]; m++) {
  296.             if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  297.                 continue;
  298.             }

  299.             module = ngx_modules[m]->ctx;

  300.             if (module->protocol == NULL) {
  301.                 continue;
  302.             }

  303.             for (i = 0; module->protocol->port[i]; i++) {
  304.                 if (module->protocol->port[i] == u.port) {
  305.                     cscf->protocol = module->protocol;
  306.                     break;
  307.                 }
  308.             }
  309.         }
  310.     }

  311.     for (i = 2; i < cf->args->nelts; i++) {

  312.         if (ngx_strcmp(value[i].data, "bind") == 0) {
  313.             ls->bind = 1;
  314.             continue;
  315.         }

  316.         if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
  317. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  318.             struct sockaddr  *sa;
  319.             u_char            buf[NGX_SOCKADDR_STRLEN];

  320.             sa = (struct sockaddr *) ls->sockaddr;

  321.             if (sa->sa_family == AF_INET6) {

  322.                 if (ngx_strcmp(&value[i].data[10], "n") == 0) {
  323.                     ls->ipv6only = 1;

  324.                 } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
  325.                     ls->ipv6only = 0;

  326.                 } else {
  327.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  328.                                        "invalid ipv6only flags \"%s\"",
  329.                                        &value[i].data[9]);
  330.                     return NGX_CONF_ERROR;
  331.                 }

  332.                 ls->bind = 1;

  333.             } else {
  334.                 len = ngx_sock_ntop(sa, ls->socklen, buf,
  335.                                     NGX_SOCKADDR_STRLEN, 1);

  336.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  337.                                    "ipv6only is not supported "
  338.                                    "on addr \"%*s\", ignored", len, buf);
  339.             }

  340.             continue;
  341. #else
  342.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  343.                                "bind ipv6only is not supported "
  344.                                "on this platform");
  345.             return NGX_CONF_ERROR;
  346. #endif
  347.         }

  348.         if (ngx_strcmp(value[i].data, "ssl") == 0) {
  349. #if (NGX_MAIL_SSL)
  350.             ls->ssl = 1;
  351.             continue;
  352. #else
  353.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  354.                                "the \"ssl\" parameter requires "
  355.                                "ngx_mail_ssl_module");
  356.             return NGX_CONF_ERROR;
  357. #endif
  358.         }

  359.         if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {

  360.             if (ngx_strcmp(&value[i].data[13], "on") == 0) {
  361.                 ls->so_keepalive = 1;

  362.             } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
  363.                 ls->so_keepalive = 2;

  364.             } else {

  365. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  366.                 u_char     *p, *end;
  367.                 ngx_str_t   s;

  368.                 end = value[i].data + value[i].len;
  369.                 s.data = value[i].data + 13;

  370.                 p = ngx_strlchr(s.data, end, ':');
  371.                 if (p == NULL) {
  372.                     p = end;
  373.                 }

  374.                 if (p > s.data) {
  375.                     s.len = p - s.data;

  376.                     ls->tcp_keepidle = ngx_parse_time(&s, 1);
  377.                     if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
  378.                         goto invalid_so_keepalive;
  379.                     }
  380.                 }

  381.                 s.data = (p < end) ? (p + 1) : end;

  382.                 p = ngx_strlchr(s.data, end, ':');
  383.                 if (p == NULL) {
  384.                     p = end;
  385.                 }

  386.                 if (p > s.data) {
  387.                     s.len = p - s.data;

  388.                     ls->tcp_keepintvl = ngx_parse_time(&s, 1);
  389.                     if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
  390.                         goto invalid_so_keepalive;
  391.                     }
  392.                 }

  393.                 s.data = (p < end) ? (p + 1) : end;

  394.                 if (s.data < end) {
  395.                     s.len = end - s.data;

  396.                     ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
  397.                     if (ls->tcp_keepcnt == NGX_ERROR) {
  398.                         goto invalid_so_keepalive;
  399.                     }
  400.                 }

  401.                 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
  402.                     && ls->tcp_keepcnt == 0)
  403.                 {
  404.                     goto invalid_so_keepalive;
  405.                 }

  406.                 ls->so_keepalive = 1;

  407. #else

  408.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  409.                                    "the \"so_keepalive\" parameter accepts "
  410.                                    "only \"on\" or \"off\" on this platform");
  411.                 return NGX_CONF_ERROR;

  412. #endif
  413.             }

  414.             ls->bind = 1;

  415.             continue;

  416. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  417.         invalid_so_keepalive:

  418.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  419.                                "invalid so_keepalive value: \"%s\"",
  420.                                &value[i].data[13]);
  421.             return NGX_CONF_ERROR;
  422. #endif
  423.         }

  424.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  425.                            "the invalid \"%V\" parameter", &value[i]);
  426.         return NGX_CONF_ERROR;
  427.     }

  428.     return NGX_CONF_OK;
  429. }


  430. static char *
  431. ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  432. {
  433.     ngx_mail_core_srv_conf_t  *cscf = conf;

  434.     ngx_str_t          *value;
  435.     ngx_uint_t          m;
  436.     ngx_mail_module_t  *module;

  437.     value = cf->args->elts;

  438.     for (m = 0; ngx_modules[m]; m++) {
  439.         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
  440.             continue;
  441.         }

  442.         module = ngx_modules[m]->ctx;

  443.         if (module->protocol
  444.             && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
  445.         {
  446.             cscf->protocol = module->protocol;

  447.             return NGX_CONF_OK;
  448.         }
  449.     }

  450.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  451.                        "unknown protocol \"%V\"", &value[1]);
  452.     return NGX_CONF_ERROR;
  453. }


  454. static char *
  455. ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  456. {
  457.     ngx_mail_core_srv_conf_t  *cscf = conf;

  458.     ngx_str_t  *value;

  459.     value = cf->args->elts;

  460.     if (cscf->resolver != NGX_CONF_UNSET_PTR) {
  461.         return "is duplicate";
  462.     }

  463.     if (ngx_strcmp(value[1].data, "off") == 0) {
  464.         cscf->resolver = NULL;
  465.         return NGX_CONF_OK;
  466.     }

  467.     cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
  468.     if (cscf->resolver == NULL) {
  469.         return NGX_CONF_ERROR;
  470.     }

  471.     return NGX_CONF_OK;
  472. }


  473. char *
  474. ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  475. {
  476.     char  *p = conf;

  477.     ngx_str_t    *c, *value;
  478.     ngx_uint_t    i;
  479.     ngx_array_t  *a;

  480.     a = (ngx_array_t *) (p + cmd->offset);

  481.     value = cf->args->elts;

  482.     for (i = 1; i < cf->args->nelts; i++) {
  483.         c = ngx_array_push(a);
  484.         if (c == NULL) {
  485.             return NGX_CONF_ERROR;
  486.         }

  487.         *c = value[i];
  488.     }

  489.     return NGX_CONF_OK;
  490. }