upstream nginx-0.7.36
[nginx.git] / nginx / src / mail / ngx_mail_core_module.c
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 void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
14 static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
15 static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
16     void *child);
17 static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
18     void *conf);
19 static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
20     void *conf);
21 static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
22     void *conf);
23 static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
24     void *conf);
25
26
27 static ngx_command_t  ngx_mail_core_commands[] = {
28
29     { ngx_string("server"),
30       NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
31       ngx_mail_core_server,
32       0,
33       0,
34       NULL },
35
36     { ngx_string("listen"),
37       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
38       ngx_mail_core_listen,
39       NGX_MAIL_SRV_CONF_OFFSET,
40       0,
41       NULL },
42
43     { ngx_string("protocol"),
44       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
45       ngx_mail_core_protocol,
46       NGX_MAIL_SRV_CONF_OFFSET,
47       0,
48       NULL },
49
50     { ngx_string("so_keepalive"),
51       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
52       ngx_conf_set_flag_slot,
53       NGX_MAIL_SRV_CONF_OFFSET,
54       offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
55       NULL },
56
57     { ngx_string("timeout"),
58       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
59       ngx_conf_set_msec_slot,
60       NGX_MAIL_SRV_CONF_OFFSET,
61       offsetof(ngx_mail_core_srv_conf_t, timeout),
62       NULL },
63
64     { ngx_string("server_name"),
65       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
66       ngx_conf_set_str_slot,
67       NGX_MAIL_SRV_CONF_OFFSET,
68       offsetof(ngx_mail_core_srv_conf_t, server_name),
69       NULL },
70
71     { ngx_string("resolver"),
72       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
73       ngx_mail_core_resolver,
74       NGX_MAIL_SRV_CONF_OFFSET,
75       0,
76       NULL },
77
78     { ngx_string("resolver_timeout"),
79       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
80       ngx_conf_set_msec_slot,
81       NGX_MAIL_SRV_CONF_OFFSET,
82       offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
83       NULL },
84
85       ngx_null_command
86 };
87
88
89 static ngx_mail_module_t  ngx_mail_core_module_ctx = {
90     NULL,                                  /* protocol */
91
92     ngx_mail_core_create_main_conf,        /* create main configuration */
93     NULL,                                  /* init main configuration */
94
95     ngx_mail_core_create_srv_conf,         /* create server configuration */
96     ngx_mail_core_merge_srv_conf           /* merge server configuration */
97 };
98
99
100 ngx_module_t  ngx_mail_core_module = {
101     NGX_MODULE_V1,
102     &ngx_mail_core_module_ctx,             /* module context */
103     ngx_mail_core_commands,                /* module directives */
104     NGX_MAIL_MODULE,                       /* module type */
105     NULL,                                  /* init master */
106     NULL,                                  /* init module */
107     NULL,                                  /* init process */
108     NULL,                                  /* init thread */
109     NULL,                                  /* exit thread */
110     NULL,                                  /* exit process */
111     NULL,                                  /* exit master */
112     NGX_MODULE_V1_PADDING
113 };
114
115
116 static void *
117 ngx_mail_core_create_main_conf(ngx_conf_t *cf)
118 {
119     ngx_mail_core_main_conf_t  *cmcf;
120
121     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
122     if (cmcf == NULL) {
123         return NGX_CONF_ERROR;
124     }
125
126     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
127                        sizeof(ngx_mail_core_srv_conf_t *))
128         != NGX_OK)
129     {
130         return NGX_CONF_ERROR;
131     }
132
133     if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
134         != NGX_OK)
135     {
136         return NGX_CONF_ERROR;
137     }
138
139     return cmcf;
140 }
141
142
143 static void *
144 ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
145 {
146     ngx_mail_core_srv_conf_t  *cscf;
147
148     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
149     if (cscf == NULL) {
150         return NULL;
151     }
152
153     /*
154      * set by ngx_pcalloc():
155      *
156      *     cscf->protocol = NULL;
157      */
158
159     cscf->timeout = NGX_CONF_UNSET_MSEC;
160     cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
161     cscf->so_keepalive = NGX_CONF_UNSET;
162
163     cscf->resolver = NGX_CONF_UNSET_PTR;
164
165     cscf->file_name = cf->conf_file->file.name.data;
166     cscf->line = cf->conf_file->line;
167
168     return cscf;
169 }
170
171
172 static char *
173 ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
174 {
175     ngx_mail_core_srv_conf_t *prev = parent;
176     ngx_mail_core_srv_conf_t *conf = child;
177
178     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
179     ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
180                               30000);
181
182     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
183
184
185     ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
186
187     if (conf->server_name.len == 0) {
188         conf->server_name = cf->cycle->hostname;
189     }
190
191     if (conf->protocol == NULL) {
192         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
193                       "unknown mail protocol for server in %s:%ui",
194                       conf->file_name, conf->line);
195         return NGX_CONF_ERROR;
196     }
197
198     ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);
199
200     return NGX_CONF_OK;
201 }
202
203
204 static char *
205 ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
206 {
207     char                       *rv;
208     void                       *mconf;
209     ngx_uint_t                  m;
210     ngx_conf_t                  pcf;
211     ngx_mail_module_t          *module;
212     ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
213     ngx_mail_core_srv_conf_t   *cscf, **cscfp;
214     ngx_mail_core_main_conf_t  *cmcf;
215
216     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
217     if (ctx == NULL) {
218         return NGX_CONF_ERROR;
219     }
220
221     mail_ctx = cf->ctx;
222     ctx->main_conf = mail_ctx->main_conf;
223
224     /* the server{}'s srv_conf */
225
226     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
227     if (ctx->srv_conf == NULL) {
228         return NGX_CONF_ERROR;
229     }
230
231     for (m = 0; ngx_modules[m]; m++) {
232         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
233             continue;
234         }
235
236         module = ngx_modules[m]->ctx;
237
238         if (module->create_srv_conf) {
239             mconf = module->create_srv_conf(cf);
240             if (mconf == NULL) {
241                 return NGX_CONF_ERROR;
242             }
243
244             ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
245         }
246     }
247
248     /* the server configuration context */
249
250     cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
251     cscf->ctx = ctx;
252
253     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
254
255     cscfp = ngx_array_push(&cmcf->servers);
256     if (cscfp == NULL) {
257         return NGX_CONF_ERROR;
258     }
259
260     *cscfp = cscf;
261
262
263     /* parse inside server{} */
264
265     pcf = *cf;
266     cf->ctx = ctx;
267     cf->cmd_type = NGX_MAIL_SRV_CONF;
268
269     rv = ngx_conf_parse(cf, NULL);
270
271     *cf = pcf;
272
273     return rv;
274 }
275
276
277 /* AF_INET only */
278
279 static char *
280 ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
281 {
282     ngx_mail_core_srv_conf_t  *cscf = conf;
283
284     ngx_str_t                  *value;
285     ngx_url_t                   u;
286     ngx_uint_t                  i, m;
287     ngx_mail_listen_t          *imls;
288     ngx_mail_module_t          *module;
289     ngx_mail_core_main_conf_t  *cmcf;
290
291     value = cf->args->elts;
292
293     ngx_memzero(&u, sizeof(ngx_url_t));
294
295     u.url = value[1];
296     u.listen = 1;
297
298     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
299         if (u.err) {
300             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
301                                "%s in \"%V\" of the \"listen\" directive",
302                                u.err, &u.url);
303         }
304
305         return NGX_CONF_ERROR;
306     }
307
308     if (u.family != AF_INET) {
309         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "listen supports IPv4 only");
310         return NGX_CONF_ERROR;
311     }
312
313     cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
314
315     imls = cmcf->listen.elts;
316
317     for (i = 0; i < cmcf->listen.nelts; i++) {
318
319         if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
320             continue;
321         }
322
323         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
324                            "duplicate \"%V\" address and port pair", &u.url);
325         return NGX_CONF_ERROR;
326     }
327
328     imls = ngx_array_push(&cmcf->listen);
329     if (imls == NULL) {
330         return NGX_CONF_ERROR;
331     }
332
333     ngx_memzero(imls, sizeof(ngx_mail_listen_t));
334
335     imls->addr = u.addr.in_addr;
336     imls->port = u.port;
337     imls->family = u.family;
338     imls->ctx = cf->ctx;
339
340     for (m = 0; ngx_modules[m]; m++) {
341         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
342             continue;
343         }
344
345         module = ngx_modules[m]->ctx;
346
347         if (module->protocol == NULL) {
348             continue;
349         }
350
351         for (i = 0; module->protocol->port[i]; i++) {
352             if (module->protocol->port[i] == u.port) {
353                 cscf->protocol = module->protocol;
354                 break;
355             }
356         }
357     }
358
359     for (i = 2; i < cf->args->nelts; i++) {
360
361         if (ngx_strcmp(value[i].data, "bind") == 0) {
362             imls->bind = 1;
363             continue;
364         }
365
366         if (ngx_strcmp(value[i].data, "ssl") == 0) {
367 #if (NGX_MAIL_SSL)
368             imls->ssl = 1;
369             continue;
370 #else
371             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
372                                "the \"ssl\" parameter requires "
373                                "ngx_mail_ssl_module");
374             return NGX_CONF_ERROR;
375 #endif
376         }
377
378         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
379                            "the invalid \"%V\" parameter", &value[i]);
380         return NGX_CONF_ERROR;
381     }
382
383     return NGX_CONF_OK;
384 }
385
386
387 static char *
388 ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
389 {
390     ngx_mail_core_srv_conf_t  *cscf = conf;
391
392     ngx_str_t          *value;
393     ngx_uint_t          m;
394     ngx_mail_module_t  *module;
395
396     value = cf->args->elts;
397
398     for (m = 0; ngx_modules[m]; m++) {
399         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
400             continue;
401         }
402
403         module = ngx_modules[m]->ctx;
404
405         if (module->protocol
406             && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
407         {
408             cscf->protocol = module->protocol;
409
410             return NGX_CONF_OK;
411         }
412     }
413
414     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
415                        "unknown protocol \"%V\"", &value[1]);
416     return NGX_CONF_ERROR;
417 }
418
419
420 static char *
421 ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
422 {
423     ngx_mail_core_srv_conf_t  *cscf = conf;
424
425     ngx_url_t   u;
426     ngx_str_t  *value;
427
428     value = cf->args->elts;
429
430     if (cscf->resolver != NGX_CONF_UNSET_PTR) {
431         return "is duplicate";
432     }
433
434     if (ngx_strcmp(value[1].data, "off") == 0) {
435         cscf->resolver = NULL;
436         return NGX_CONF_OK;
437     }
438
439     ngx_memzero(&u, sizeof(ngx_url_t));
440
441     u.host = value[1];
442     u.port = 53;
443
444     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
445         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
446         return NGX_CONF_ERROR;
447     }
448
449     cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
450     if (cscf->resolver == NULL) {
451         return NGX_CONF_OK;
452     }
453
454     return NGX_CONF_OK;
455 }
456
457
458 char *
459 ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
460 {
461     char  *p = conf;
462
463     ngx_str_t    *c, *value;
464     ngx_uint_t    i;
465     ngx_array_t  *a;
466
467     a = (ngx_array_t *) (p + cmd->offset);
468
469     value = cf->args->elts;
470
471     for (i = 1; i < cf->args->nelts; i++) {
472         c = ngx_array_push(a);
473         if (c == NULL) {
474             return NGX_CONF_ERROR;
475         }
476
477         *c = value[i];
478     }
479
480     return NGX_CONF_OK;
481 }