3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
10 #include <ngx_event.h>
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
);
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
);
24 static ngx_int_t
ngx_mail_cmp_conf_addrs(const void *one
, const void *two
);
27 ngx_uint_t ngx_mail_max_module
;
30 static ngx_command_t ngx_mail_commands
[] = {
33 NGX_MAIN_CONF
|NGX_CONF_BLOCK
|NGX_CONF_NOARGS
,
40 NGX_MAIN_CONF
|NGX_CONF_BLOCK
|NGX_CONF_NOARGS
,
50 static ngx_core_module_t ngx_mail_module_ctx
= {
57 ngx_module_t ngx_mail_module
= {
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 */
74 ngx_mail_block(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
77 ngx_uint_t i
, m
, mi
, s
;
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
;
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");
92 /* the main mail context */
94 ctx
= ngx_pcalloc(cf
->pool
, sizeof(ngx_mail_conf_ctx_t
));
96 return NGX_CONF_ERROR
;
99 *(ngx_mail_conf_ctx_t
**) conf
= ctx
;
101 /* count the number of the http modules and set up their indices */
103 ngx_mail_max_module
= 0;
104 for (m
= 0; ngx_modules
[m
]; m
++) {
105 if (ngx_modules
[m
]->type
!= NGX_MAIL_MODULE
) {
109 ngx_modules
[m
]->ctx_index
= ngx_mail_max_module
++;
113 /* the mail main_conf context, it is the same in the all mail contexts */
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
;
123 * the mail null srv_conf context, it is used to merge
124 * the server{}s' srv_conf's
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
;
134 * create the main_conf's, the null srv_conf's, and the null loc_conf's
135 * of the all mail modules
138 for (m
= 0; ngx_modules
[m
]; m
++) {
139 if (ngx_modules
[m
]->type
!= NGX_MAIL_MODULE
) {
143 module
= ngx_modules
[m
]->ctx
;
144 mi
= ngx_modules
[m
]->ctx_index
;
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
;
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
;
162 /* parse inside the mail{} block */
167 cf
->module_type
= NGX_MAIL_MODULE
;
168 cf
->cmd_type
= NGX_MAIL_MAIN_CONF
;
169 rv
= ngx_conf_parse(cf
, NULL
);
171 if (rv
!= NGX_CONF_OK
) {
177 /* init mail{} main_conf's, merge the server{}s' srv_conf's */
179 cmcf
= ctx
->main_conf
[ngx_mail_core_module
.ctx_index
];
180 cscfp
= cmcf
->servers
.elts
;
182 for (m
= 0; ngx_modules
[m
]; m
++) {
183 if (ngx_modules
[m
]->type
!= NGX_MAIL_MODULE
) {
187 module
= ngx_modules
[m
]->ctx
;
188 mi
= ngx_modules
[m
]->ctx_index
;
190 /* init mail{} main_conf's */
194 if (module
->init_main_conf
) {
195 rv
= module
->init_main_conf(cf
, ctx
->main_conf
[mi
]);
196 if (rv
!= NGX_CONF_OK
) {
202 for (s
= 0; s
< cmcf
->servers
.nelts
; s
++) {
204 /* merge the server{}s' srv_conf's */
206 cf
->ctx
= cscfp
[s
]->ctx
;
208 if (module
->merge_srv_conf
) {
209 rv
= module
->merge_srv_conf(cf
,
211 cscfp
[s
]->ctx
->srv_conf
[mi
]);
212 if (rv
!= NGX_CONF_OK
) {
223 if (ngx_array_init(&ports
, cf
->temp_pool
, 4, sizeof(ngx_mail_conf_port_t
))
226 return NGX_CONF_ERROR
;
229 listen
= cmcf
->listen
.elts
;
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
;
237 return ngx_mail_optimize_servers(cf
, &ports
);
242 ngx_mail_add_ports(ngx_conf_t
*cf
, ngx_array_t
*ports
,
243 ngx_mail_listen_t
*listen
)
248 struct sockaddr_in
*sin
;
249 ngx_mail_conf_port_t
*port
;
250 ngx_mail_conf_addr_t
*addr
;
252 struct sockaddr_in6
*sin6
;
255 sa
= (struct sockaddr
*) &listen
->sockaddr
;
257 switch (sa
->sa_family
) {
261 sin6
= (struct sockaddr_in6
*) sa
;
266 #if (NGX_HAVE_UNIX_DOMAIN)
272 default: /* AF_INET */
273 sin
= (struct sockaddr_in
*) sa
;
279 for (i
= 0; i
< ports
->nelts
; i
++) {
280 if (p
== port
[i
].port
&& sa
->sa_family
== port
[i
].family
) {
282 /* a port is already in the port list */
289 /* add a port to the port list */
291 port
= ngx_array_push(ports
);
296 port
->family
= sa
->sa_family
;
299 if (ngx_array_init(&port
->addrs
, cf
->temp_pool
, 2,
300 sizeof(ngx_mail_conf_addr_t
))
308 addr
= ngx_array_push(&port
->addrs
);
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
;
325 addr
->ssl
= listen
->ssl
;
327 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
328 addr
->ipv6only
= listen
->ipv6only
;
336 ngx_mail_optimize_servers(ngx_conf_t
*cf
, ngx_array_t
*ports
)
338 ngx_uint_t i
, p
, last
, bind_wildcard
;
340 ngx_mail_port_t
*mport
;
341 ngx_mail_conf_port_t
*port
;
342 ngx_mail_conf_addr_t
*addr
;
345 for (p
= 0; p
< ports
->nelts
; p
++) {
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
);
350 addr
= port
[p
].addrs
.elts
;
351 last
= port
[p
].addrs
.nelts
;
354 * if there is the binding to the "*:port" then we need to bind()
355 * to the "*:port" only and ignore the other bindings
358 if (addr
[last
- 1].wildcard
) {
359 addr
[last
- 1].bind
= 1;
370 if (bind_wildcard
&& !addr
[i
].bind
) {
375 ls
= ngx_create_listening(cf
, addr
[i
].sockaddr
, addr
[i
].socklen
);
377 return NGX_CONF_ERROR
;
381 ls
->handler
= ngx_mail_init_connection
;
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
;
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
;
396 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
397 ls
->ipv6only
= addr
[i
].ipv6only
;
400 mport
= ngx_palloc(cf
->pool
, sizeof(ngx_mail_port_t
));
402 return NGX_CONF_ERROR
;
408 mport
->naddrs
= last
;
415 switch (ls
->sockaddr
->sa_family
) {
418 if (ngx_mail_add_addrs6(cf
, mport
, addr
) != NGX_OK
) {
419 return NGX_CONF_ERROR
;
423 default: /* AF_INET */
424 if (ngx_mail_add_addrs(cf
, mport
, addr
) != NGX_OK
) {
425 return NGX_CONF_ERROR
;
440 ngx_mail_add_addrs(ngx_conf_t
*cf
, ngx_mail_port_t
*mport
,
441 ngx_mail_conf_addr_t
*addr
)
446 ngx_mail_in_addr_t
*addrs
;
447 struct sockaddr_in
*sin
;
448 u_char buf
[NGX_SOCKADDR_STRLEN
];
450 mport
->addrs
= ngx_pcalloc(cf
->pool
,
451 mport
->naddrs
* sizeof(ngx_mail_in_addr_t
));
452 if (mport
->addrs
== NULL
) {
456 addrs
= mport
->addrs
;
458 for (i
= 0; i
< mport
->naddrs
; i
++) {
460 sin
= (struct sockaddr_in
*) addr
[i
].sockaddr
;
461 addrs
[i
].addr
= sin
->sin_addr
.s_addr
;
463 addrs
[i
].conf
.ctx
= addr
[i
].ctx
;
465 addrs
[i
].conf
.ssl
= addr
[i
].ssl
;
468 len
= ngx_sock_ntop(addr
[i
].sockaddr
, buf
, NGX_SOCKADDR_STRLEN
, 1);
470 p
= ngx_pnalloc(cf
->pool
, len
);
475 ngx_memcpy(p
, buf
, len
);
477 addrs
[i
].conf
.addr_text
.len
= len
;
478 addrs
[i
].conf
.addr_text
.data
= p
;
488 ngx_mail_add_addrs6(ngx_conf_t
*cf
, ngx_mail_port_t
*mport
,
489 ngx_mail_conf_addr_t
*addr
)
494 ngx_mail_in6_addr_t
*addrs6
;
495 struct sockaddr_in6
*sin6
;
496 u_char buf
[NGX_SOCKADDR_STRLEN
];
498 mport
->addrs
= ngx_pcalloc(cf
->pool
,
499 mport
->naddrs
* sizeof(ngx_mail_in6_addr_t
));
500 if (mport
->addrs
== NULL
) {
504 addrs6
= mport
->addrs
;
506 for (i
= 0; i
< mport
->naddrs
; i
++) {
508 sin6
= (struct sockaddr_in6
*) addr
[i
].sockaddr
;
509 addrs6
[i
].addr6
= sin6
->sin6_addr
;
511 addrs6
[i
].conf
.ctx
= addr
[i
].ctx
;
513 addrs6
[i
].conf
.ssl
= addr
[i
].ssl
;
516 len
= ngx_sock_ntop(addr
[i
].sockaddr
, buf
, NGX_SOCKADDR_STRLEN
, 1);
518 p
= ngx_pnalloc(cf
->pool
, len
);
523 ngx_memcpy(p
, buf
, len
);
525 addrs6
[i
].conf
.addr_text
.len
= len
;
526 addrs6
[i
].conf
.addr_text
.data
= p
;
536 ngx_mail_cmp_conf_addrs(const void *one
, const void *two
)
538 ngx_mail_conf_addr_t
*first
, *second
;
540 first
= (ngx_mail_conf_addr_t
*) one
;
541 second
= (ngx_mail_conf_addr_t
*) two
;
543 if (first
->wildcard
) {
544 /* a wildcard must be the last resort, shift it to the end */
548 if (second
->wildcard
) {
549 /* a wildcard must be the last resort, shift it to the end */
553 if (first
->bind
&& !second
->bind
) {
554 /* shift explicit bind()ed addresses to the start */
558 if (!first
->bind
&& second
->bind
) {
559 /* shift explicit bind()ed addresses to the start */
563 /* do not sort by default */