Annotation of embedaddon/nginx/src/mail/ngx_mail.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (C) Igor Sysoev
        !             4:  * Copyright (C) Nginx, Inc.
        !             5:  */
        !             6: 
        !             7: 
        !             8: #include <ngx_config.h>
        !             9: #include <ngx_core.h>
        !            10: #include <ngx_event.h>
        !            11: #include <ngx_mail.h>
        !            12: 
        !            13: 
        !            14: static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
        !            15: static ngx_int_t ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
        !            16:     ngx_mail_listen_t *listen);
        !            17: static char *ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports);
        !            18: static ngx_int_t ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
        !            19:     ngx_mail_conf_addr_t *addr);
        !            20: #if (NGX_HAVE_INET6)
        !            21: static ngx_int_t ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
        !            22:     ngx_mail_conf_addr_t *addr);
        !            23: #endif
        !            24: static ngx_int_t ngx_mail_cmp_conf_addrs(const void *one, const void *two);
        !            25: 
        !            26: 
        !            27: ngx_uint_t  ngx_mail_max_module;
        !            28: 
        !            29: 
        !            30: static ngx_command_t  ngx_mail_commands[] = {
        !            31: 
        !            32:     { ngx_string("mail"),
        !            33:       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
        !            34:       ngx_mail_block,
        !            35:       0,
        !            36:       0,
        !            37:       NULL },
        !            38: 
        !            39:     { ngx_string("imap"),
        !            40:       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
        !            41:       ngx_mail_block,
        !            42:       0,
        !            43:       0,
        !            44:       NULL },
        !            45: 
        !            46:       ngx_null_command
        !            47: };
        !            48: 
        !            49: 
        !            50: static ngx_core_module_t  ngx_mail_module_ctx = {
        !            51:     ngx_string("mail"),
        !            52:     NULL,
        !            53:     NULL
        !            54: };
        !            55: 
        !            56: 
        !            57: ngx_module_t  ngx_mail_module = {
        !            58:     NGX_MODULE_V1,
        !            59:     &ngx_mail_module_ctx,                  /* module context */
        !            60:     ngx_mail_commands,                     /* module directives */
        !            61:     NGX_CORE_MODULE,                       /* module type */
        !            62:     NULL,                                  /* init master */
        !            63:     NULL,                                  /* init module */
        !            64:     NULL,                                  /* init process */
        !            65:     NULL,                                  /* init thread */
        !            66:     NULL,                                  /* exit thread */
        !            67:     NULL,                                  /* exit process */
        !            68:     NULL,                                  /* exit master */
        !            69:     NGX_MODULE_V1_PADDING
        !            70: };
        !            71: 
        !            72: 
        !            73: static char *
        !            74: ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
        !            75: {
        !            76:     char                        *rv;
        !            77:     ngx_uint_t                   i, m, mi, s;
        !            78:     ngx_conf_t                   pcf;
        !            79:     ngx_array_t                  ports;
        !            80:     ngx_mail_listen_t           *listen;
        !            81:     ngx_mail_module_t           *module;
        !            82:     ngx_mail_conf_ctx_t         *ctx;
        !            83:     ngx_mail_core_srv_conf_t   **cscfp;
        !            84:     ngx_mail_core_main_conf_t   *cmcf;
        !            85: 
        !            86:     if (cmd->name.data[0] == 'i') {
        !            87:         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
        !            88:                            "the \"imap\" directive is deprecated, "
        !            89:                            "use the \"mail\" directive instead");
        !            90:     }
        !            91: 
        !            92:     /* the main mail context */
        !            93: 
        !            94:     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
        !            95:     if (ctx == NULL) {
        !            96:         return NGX_CONF_ERROR;
        !            97:     }
        !            98: 
        !            99:     *(ngx_mail_conf_ctx_t **) conf = ctx;
        !           100: 
        !           101:     /* count the number of the http modules and set up their indices */
        !           102: 
        !           103:     ngx_mail_max_module = 0;
        !           104:     for (m = 0; ngx_modules[m]; m++) {
        !           105:         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
        !           106:             continue;
        !           107:         }
        !           108: 
        !           109:         ngx_modules[m]->ctx_index = ngx_mail_max_module++;
        !           110:     }
        !           111: 
        !           112: 
        !           113:     /* the mail main_conf context, it is the same in the all mail contexts */
        !           114: 
        !           115:     ctx->main_conf = ngx_pcalloc(cf->pool,
        !           116:                                  sizeof(void *) * ngx_mail_max_module);
        !           117:     if (ctx->main_conf == NULL) {
        !           118:         return NGX_CONF_ERROR;
        !           119:     }
        !           120: 
        !           121: 
        !           122:     /*
        !           123:      * the mail null srv_conf context, it is used to merge
        !           124:      * the server{}s' srv_conf's
        !           125:      */
        !           126: 
        !           127:     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
        !           128:     if (ctx->srv_conf == NULL) {
        !           129:         return NGX_CONF_ERROR;
        !           130:     }
        !           131: 
        !           132: 
        !           133:     /*
        !           134:      * create the main_conf's, the null srv_conf's, and the null loc_conf's
        !           135:      * of the all mail modules
        !           136:      */
        !           137: 
        !           138:     for (m = 0; ngx_modules[m]; m++) {
        !           139:         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
        !           140:             continue;
        !           141:         }
        !           142: 
        !           143:         module = ngx_modules[m]->ctx;
        !           144:         mi = ngx_modules[m]->ctx_index;
        !           145: 
        !           146:         if (module->create_main_conf) {
        !           147:             ctx->main_conf[mi] = module->create_main_conf(cf);
        !           148:             if (ctx->main_conf[mi] == NULL) {
        !           149:                 return NGX_CONF_ERROR;
        !           150:             }
        !           151:         }
        !           152: 
        !           153:         if (module->create_srv_conf) {
        !           154:             ctx->srv_conf[mi] = module->create_srv_conf(cf);
        !           155:             if (ctx->srv_conf[mi] == NULL) {
        !           156:                 return NGX_CONF_ERROR;
        !           157:             }
        !           158:         }
        !           159:     }
        !           160: 
        !           161: 
        !           162:     /* parse inside the mail{} block */
        !           163: 
        !           164:     pcf = *cf;
        !           165:     cf->ctx = ctx;
        !           166: 
        !           167:     cf->module_type = NGX_MAIL_MODULE;
        !           168:     cf->cmd_type = NGX_MAIL_MAIN_CONF;
        !           169:     rv = ngx_conf_parse(cf, NULL);
        !           170: 
        !           171:     if (rv != NGX_CONF_OK) {
        !           172:         *cf = pcf;
        !           173:         return rv;
        !           174:     }
        !           175: 
        !           176: 
        !           177:     /* init mail{} main_conf's, merge the server{}s' srv_conf's */
        !           178: 
        !           179:     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
        !           180:     cscfp = cmcf->servers.elts;
        !           181: 
        !           182:     for (m = 0; ngx_modules[m]; m++) {
        !           183:         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
        !           184:             continue;
        !           185:         }
        !           186: 
        !           187:         module = ngx_modules[m]->ctx;
        !           188:         mi = ngx_modules[m]->ctx_index;
        !           189: 
        !           190:         /* init mail{} main_conf's */
        !           191: 
        !           192:         cf->ctx = ctx;
        !           193: 
        !           194:         if (module->init_main_conf) {
        !           195:             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
        !           196:             if (rv != NGX_CONF_OK) {
        !           197:                 *cf = pcf;
        !           198:                 return rv;
        !           199:             }
        !           200:         }
        !           201: 
        !           202:         for (s = 0; s < cmcf->servers.nelts; s++) {
        !           203: 
        !           204:             /* merge the server{}s' srv_conf's */
        !           205: 
        !           206:             cf->ctx = cscfp[s]->ctx;
        !           207: 
        !           208:             if (module->merge_srv_conf) {
        !           209:                 rv = module->merge_srv_conf(cf,
        !           210:                                             ctx->srv_conf[mi],
        !           211:                                             cscfp[s]->ctx->srv_conf[mi]);
        !           212:                 if (rv != NGX_CONF_OK) {
        !           213:                     *cf = pcf;
        !           214:                     return rv;
        !           215:                 }
        !           216:             }
        !           217:         }
        !           218:     }
        !           219: 
        !           220:     *cf = pcf;
        !           221: 
        !           222: 
        !           223:     if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
        !           224:         != NGX_OK)
        !           225:     {
        !           226:         return NGX_CONF_ERROR;
        !           227:     }
        !           228: 
        !           229:     listen = cmcf->listen.elts;
        !           230: 
        !           231:     for (i = 0; i < cmcf->listen.nelts; i++) {
        !           232:         if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
        !           233:             return NGX_CONF_ERROR;
        !           234:         }
        !           235:     }
        !           236: 
        !           237:     return ngx_mail_optimize_servers(cf, &ports);
        !           238: }
        !           239: 
        !           240: 
        !           241: static ngx_int_t
        !           242: ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
        !           243:     ngx_mail_listen_t *listen)
        !           244: {
        !           245:     in_port_t              p;
        !           246:     ngx_uint_t             i;
        !           247:     struct sockaddr       *sa;
        !           248:     struct sockaddr_in    *sin;
        !           249:     ngx_mail_conf_port_t  *port;
        !           250:     ngx_mail_conf_addr_t  *addr;
        !           251: #if (NGX_HAVE_INET6)
        !           252:     struct sockaddr_in6   *sin6;
        !           253: #endif
        !           254: 
        !           255:     sa = (struct sockaddr *) &listen->sockaddr;
        !           256: 
        !           257:     switch (sa->sa_family) {
        !           258: 
        !           259: #if (NGX_HAVE_INET6)
        !           260:     case AF_INET6:
        !           261:         sin6 = (struct sockaddr_in6 *) sa;
        !           262:         p = sin6->sin6_port;
        !           263:         break;
        !           264: #endif
        !           265: 
        !           266: #if (NGX_HAVE_UNIX_DOMAIN)
        !           267:     case AF_UNIX:
        !           268:         p = 0;
        !           269:         break;
        !           270: #endif
        !           271: 
        !           272:     default: /* AF_INET */
        !           273:         sin = (struct sockaddr_in *) sa;
        !           274:         p = sin->sin_port;
        !           275:         break;
        !           276:     }
        !           277: 
        !           278:     port = ports->elts;
        !           279:     for (i = 0; i < ports->nelts; i++) {
        !           280:         if (p == port[i].port && sa->sa_family == port[i].family) {
        !           281: 
        !           282:             /* a port is already in the port list */
        !           283: 
        !           284:             port = &port[i];
        !           285:             goto found;
        !           286:         }
        !           287:     }
        !           288: 
        !           289:     /* add a port to the port list */
        !           290: 
        !           291:     port = ngx_array_push(ports);
        !           292:     if (port == NULL) {
        !           293:         return NGX_ERROR;
        !           294:     }
        !           295: 
        !           296:     port->family = sa->sa_family;
        !           297:     port->port = p;
        !           298: 
        !           299:     if (ngx_array_init(&port->addrs, cf->temp_pool, 2,
        !           300:                        sizeof(ngx_mail_conf_addr_t))
        !           301:         != NGX_OK)
        !           302:     {
        !           303:         return NGX_ERROR;
        !           304:     }
        !           305: 
        !           306: found:
        !           307: 
        !           308:     addr = ngx_array_push(&port->addrs);
        !           309:     if (addr == NULL) {
        !           310:         return NGX_ERROR;
        !           311:     }
        !           312: 
        !           313:     addr->sockaddr = (struct sockaddr *) &listen->sockaddr;
        !           314:     addr->socklen = listen->socklen;
        !           315:     addr->ctx = listen->ctx;
        !           316:     addr->bind = listen->bind;
        !           317:     addr->wildcard = listen->wildcard;
        !           318:     addr->so_keepalive = listen->so_keepalive;
        !           319: #if (NGX_HAVE_KEEPALIVE_TUNABLE)
        !           320:     addr->tcp_keepidle = listen->tcp_keepidle;
        !           321:     addr->tcp_keepintvl = listen->tcp_keepintvl;
        !           322:     addr->tcp_keepcnt = listen->tcp_keepcnt;
        !           323: #endif
        !           324: #if (NGX_MAIL_SSL)
        !           325:     addr->ssl = listen->ssl;
        !           326: #endif
        !           327: #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
        !           328:     addr->ipv6only = listen->ipv6only;
        !           329: #endif
        !           330: 
        !           331:     return NGX_OK;
        !           332: }
        !           333: 
        !           334: 
        !           335: static char *
        !           336: ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
        !           337: {
        !           338:     ngx_uint_t             i, p, last, bind_wildcard;
        !           339:     ngx_listening_t       *ls;
        !           340:     ngx_mail_port_t       *mport;
        !           341:     ngx_mail_conf_port_t  *port;
        !           342:     ngx_mail_conf_addr_t  *addr;
        !           343: 
        !           344:     port = ports->elts;
        !           345:     for (p = 0; p < ports->nelts; p++) {
        !           346: 
        !           347:         ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts,
        !           348:                  sizeof(ngx_mail_conf_addr_t), ngx_mail_cmp_conf_addrs);
        !           349: 
        !           350:         addr = port[p].addrs.elts;
        !           351:         last = port[p].addrs.nelts;
        !           352: 
        !           353:         /*
        !           354:          * if there is the binding to the "*:port" then we need to bind()
        !           355:          * to the "*:port" only and ignore the other bindings
        !           356:          */
        !           357: 
        !           358:         if (addr[last - 1].wildcard) {
        !           359:             addr[last - 1].bind = 1;
        !           360:             bind_wildcard = 1;
        !           361: 
        !           362:         } else {
        !           363:             bind_wildcard = 0;
        !           364:         }
        !           365: 
        !           366:         i = 0;
        !           367: 
        !           368:         while (i < last) {
        !           369: 
        !           370:             if (bind_wildcard && !addr[i].bind) {
        !           371:                 i++;
        !           372:                 continue;
        !           373:             }
        !           374: 
        !           375:             ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
        !           376:             if (ls == NULL) {
        !           377:                 return NGX_CONF_ERROR;
        !           378:             }
        !           379: 
        !           380:             ls->addr_ntop = 1;
        !           381:             ls->handler = ngx_mail_init_connection;
        !           382:             ls->pool_size = 256;
        !           383: 
        !           384:             /* TODO: error_log directive */
        !           385:             ls->logp = &cf->cycle->new_log;
        !           386:             ls->log.data = &ls->addr_text;
        !           387:             ls->log.handler = ngx_accept_log_error;
        !           388: 
        !           389:             ls->keepalive = addr[i].so_keepalive;
        !           390: #if (NGX_HAVE_KEEPALIVE_TUNABLE)
        !           391:             ls->keepidle = addr[i].tcp_keepidle;
        !           392:             ls->keepintvl = addr[i].tcp_keepintvl;
        !           393:             ls->keepcnt = addr[i].tcp_keepcnt;
        !           394: #endif
        !           395: 
        !           396: #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
        !           397:             ls->ipv6only = addr[i].ipv6only;
        !           398: #endif
        !           399: 
        !           400:             mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
        !           401:             if (mport == NULL) {
        !           402:                 return NGX_CONF_ERROR;
        !           403:             }
        !           404: 
        !           405:             ls->servers = mport;
        !           406: 
        !           407:             if (i == last - 1) {
        !           408:                 mport->naddrs = last;
        !           409: 
        !           410:             } else {
        !           411:                 mport->naddrs = 1;
        !           412:                 i = 0;
        !           413:             }
        !           414: 
        !           415:             switch (ls->sockaddr->sa_family) {
        !           416: #if (NGX_HAVE_INET6)
        !           417:             case AF_INET6:
        !           418:                 if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
        !           419:                     return NGX_CONF_ERROR;
        !           420:                 }
        !           421:                 break;
        !           422: #endif
        !           423:             default: /* AF_INET */
        !           424:                 if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
        !           425:                     return NGX_CONF_ERROR;
        !           426:                 }
        !           427:                 break;
        !           428:             }
        !           429: 
        !           430:             addr++;
        !           431:             last--;
        !           432:         }
        !           433:     }
        !           434: 
        !           435:     return NGX_CONF_OK;
        !           436: }
        !           437: 
        !           438: 
        !           439: static ngx_int_t
        !           440: ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
        !           441:     ngx_mail_conf_addr_t *addr)
        !           442: {
        !           443:     u_char              *p;
        !           444:     size_t               len;
        !           445:     ngx_uint_t           i;
        !           446:     ngx_mail_in_addr_t  *addrs;
        !           447:     struct sockaddr_in  *sin;
        !           448:     u_char               buf[NGX_SOCKADDR_STRLEN];
        !           449: 
        !           450:     mport->addrs = ngx_pcalloc(cf->pool,
        !           451:                                mport->naddrs * sizeof(ngx_mail_in_addr_t));
        !           452:     if (mport->addrs == NULL) {
        !           453:         return NGX_ERROR;
        !           454:     }
        !           455: 
        !           456:     addrs = mport->addrs;
        !           457: 
        !           458:     for (i = 0; i < mport->naddrs; i++) {
        !           459: 
        !           460:         sin = (struct sockaddr_in *) addr[i].sockaddr;
        !           461:         addrs[i].addr = sin->sin_addr.s_addr;
        !           462: 
        !           463:         addrs[i].conf.ctx = addr[i].ctx;
        !           464: #if (NGX_MAIL_SSL)
        !           465:         addrs[i].conf.ssl = addr[i].ssl;
        !           466: #endif
        !           467: 
        !           468:         len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
        !           469: 
        !           470:         p = ngx_pnalloc(cf->pool, len);
        !           471:         if (p == NULL) {
        !           472:             return NGX_ERROR;
        !           473:         }
        !           474: 
        !           475:         ngx_memcpy(p, buf, len);
        !           476: 
        !           477:         addrs[i].conf.addr_text.len = len;
        !           478:         addrs[i].conf.addr_text.data = p;
        !           479:     }
        !           480: 
        !           481:     return NGX_OK;
        !           482: }
        !           483: 
        !           484: 
        !           485: #if (NGX_HAVE_INET6)
        !           486: 
        !           487: static ngx_int_t
        !           488: ngx_mail_add_addrs6(ngx_conf_t *cf, ngx_mail_port_t *mport,
        !           489:     ngx_mail_conf_addr_t *addr)
        !           490: {
        !           491:     u_char               *p;
        !           492:     size_t                len;
        !           493:     ngx_uint_t            i;
        !           494:     ngx_mail_in6_addr_t  *addrs6;
        !           495:     struct sockaddr_in6  *sin6;
        !           496:     u_char                buf[NGX_SOCKADDR_STRLEN];
        !           497: 
        !           498:     mport->addrs = ngx_pcalloc(cf->pool,
        !           499:                                mport->naddrs * sizeof(ngx_mail_in6_addr_t));
        !           500:     if (mport->addrs == NULL) {
        !           501:         return NGX_ERROR;
        !           502:     }
        !           503: 
        !           504:     addrs6 = mport->addrs;
        !           505: 
        !           506:     for (i = 0; i < mport->naddrs; i++) {
        !           507: 
        !           508:         sin6 = (struct sockaddr_in6 *) addr[i].sockaddr;
        !           509:         addrs6[i].addr6 = sin6->sin6_addr;
        !           510: 
        !           511:         addrs6[i].conf.ctx = addr[i].ctx;
        !           512: #if (NGX_MAIL_SSL)
        !           513:         addrs6[i].conf.ssl = addr[i].ssl;
        !           514: #endif
        !           515: 
        !           516:         len = ngx_sock_ntop(addr[i].sockaddr, buf, NGX_SOCKADDR_STRLEN, 1);
        !           517: 
        !           518:         p = ngx_pnalloc(cf->pool, len);
        !           519:         if (p == NULL) {
        !           520:             return NGX_ERROR;
        !           521:         }
        !           522: 
        !           523:         ngx_memcpy(p, buf, len);
        !           524: 
        !           525:         addrs6[i].conf.addr_text.len = len;
        !           526:         addrs6[i].conf.addr_text.data = p;
        !           527:     }
        !           528: 
        !           529:     return NGX_OK;
        !           530: }
        !           531: 
        !           532: #endif
        !           533: 
        !           534: 
        !           535: static ngx_int_t
        !           536: ngx_mail_cmp_conf_addrs(const void *one, const void *two)
        !           537: {
        !           538:     ngx_mail_conf_addr_t  *first, *second;
        !           539: 
        !           540:     first = (ngx_mail_conf_addr_t *) one;
        !           541:     second = (ngx_mail_conf_addr_t *) two;
        !           542: 
        !           543:     if (first->wildcard) {
        !           544:         /* a wildcard must be the last resort, shift it to the end */
        !           545:         return 1;
        !           546:     }
        !           547: 
        !           548:     if (second->wildcard) {
        !           549:         /* a wildcard must be the last resort, shift it to the end */
        !           550:         return -1;
        !           551:     }
        !           552: 
        !           553:     if (first->bind && !second->bind) {
        !           554:         /* shift explicit bind()ed addresses to the start */
        !           555:         return -1;
        !           556:     }
        !           557: 
        !           558:     if (!first->bind && second->bind) {
        !           559:         /* shift explicit bind()ed addresses to the start */
        !           560:         return 1;
        !           561:     }
        !           562: 
        !           563:     /* do not sort by default */
        !           564: 
        !           565:     return 0;
        !           566: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>