Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_mail.c
Go to the documentation of this file.
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 
28 
29 
30 static ngx_command_t ngx_mail_commands[] = {
31 
32  { ngx_string("mail"),
34  ngx_mail_block,
35  0,
36  0,
37  NULL },
38 
39  { ngx_string("imap"),
41  ngx_mail_block,
42  0,
43  0,
44  NULL },
45 
47 };
48 
49 
50 static ngx_core_module_t ngx_mail_module_ctx = {
51  ngx_string("mail"),
52  NULL,
53  NULL
54 };
55 
56 
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 */
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;
85 
86  if (cmd->name.data[0] == 'i') {
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 
104  for (m = 0; ngx_modules[m]; m++) {
105  if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
106  continue;
107  }
108 
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 
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 
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;
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;
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;
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 }