Annotation of embedaddon/nginx/src/mail/ngx_mail.c, revision 1.1.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>