~nginx/nginx/1.0

« back to all changes in this revision

Viewing changes to src/mail/ngx_mail.c

  • Committer: Michael Lustfield
  • Date: 2010-12-01 08:06:25 UTC
  • Revision ID: michael@profarius.com-20101201080625-y8i4bq0e54ev2qwy
Tags: 0.9.0
Nginx v0.9.0

Show diffs side-by-side

added added

removed removed

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