10e6c8b5e824dd9ade3bc3ed459480fd4257b2ef
[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     cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
309
310     imls = cmcf->listen.elts;
311
312     for (i = 0; i < cmcf->listen.nelts; i++) {
313
314         if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
315             continue;
316         }
317
318         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
319                            "duplicate \"%V\" address and port pair", &u.url);
320         return NGX_CONF_ERROR;
321     }
322
323     imls = ngx_array_push(&cmcf->listen);
324     if (imls == NULL) {
325         return NGX_CONF_ERROR;
326     }
327
328     ngx_memzero(imls, sizeof(ngx_mail_listen_t));
329
330     imls->addr = u.addr.in_addr;
331     imls->port = u.port;
332     imls->family = u.family;
333     imls->ctx = cf->ctx;
334
335     for (m = 0; ngx_modules[m]; m++) {
336         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
337             continue;
338         }
339
340         module = ngx_modules[m]->ctx;
341
342         if (module->protocol == NULL) {
343             continue;
344         }
345
346         for (i = 0; module->protocol->port[i]; i++) {
347             if (module->protocol->port[i] == u.port) {
348                 cscf->protocol = module->protocol;
349                 break;
350             }
351         }
352     }
353
354     for (i = 2; i < cf->args->nelts; i++) {
355
356         if (ngx_strcmp(value[i].data, "bind") == 0) {
357             imls->bind = 1;
358             continue;
359         }
360
361         if (ngx_strcmp(value[i].data, "ssl") == 0) {
362 #if (NGX_MAIL_SSL)
363             imls->ssl = 1;
364             continue;
365 #else
366             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
367                                "the \"ssl\" parameter requires "
368                                "ngx_mail_ssl_module");
369             return NGX_CONF_ERROR;
370 #endif
371         }
372
373         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
374                            "the invalid \"%V\" parameter", &value[i]);
375         return NGX_CONF_ERROR;
376     }
377
378     return NGX_CONF_OK;
379 }
380
381
382 static char *
383 ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
384 {
385     ngx_mail_core_srv_conf_t  *cscf = conf;
386
387     ngx_str_t          *value;
388     ngx_uint_t          m;
389     ngx_mail_module_t  *module;
390
391     value = cf->args->elts;
392
393     for (m = 0; ngx_modules[m]; m++) {
394         if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
395             continue;
396         }
397
398         module = ngx_modules[m]->ctx;
399
400         if (module->protocol
401             && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
402         {
403             cscf->protocol = module->protocol;
404
405             return NGX_CONF_OK;
406         }
407     }
408
409     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
410                        "unknown protocol \"%V\"", &value[1]);
411     return NGX_CONF_ERROR;
412 }
413
414
415 static char *
416 ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
417 {
418     ngx_mail_core_srv_conf_t  *cscf = conf;
419
420     ngx_url_t   u;
421     ngx_str_t  *value;
422
423     value = cf->args->elts;
424
425     if (cscf->resolver != NGX_CONF_UNSET_PTR) {
426         return "is duplicate";
427     }
428
429     if (ngx_strcmp(value[1].data, "off") == 0) {
430         cscf->resolver = NULL;
431         return NGX_CONF_OK;
432     }
433
434     ngx_memzero(&u, sizeof(ngx_url_t));
435
436     u.host = value[1];
437     u.port = 53;
438
439     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
440         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err);
441         return NGX_CONF_ERROR;
442     }
443
444     cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]);
445     if (cscf->resolver == NULL) {
446         return NGX_CONF_OK;
447     }
448
449     return NGX_CONF_OK;
450 }
451
452
453 char *
454 ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
455 {
456     char  *p = conf;
457
458     ngx_str_t    *c, *value;
459     ngx_uint_t    i;
460     ngx_array_t  *a;
461
462     a = (ngx_array_t *) (p + cmd->offset);
463
464     value = cf->args->elts;
465
466     for (i = 1; i < cf->args->nelts; i++) {
467         c = ngx_array_push(a);
468         if (c == NULL) {
469             return NGX_CONF_ERROR;
470         }
471
472         *c = value[i];
473     }
474
475     return NGX_CONF_OK;
476 }