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>