comparison src/mail/ngx_mail.c @ 492:98143f74eb3d NGINX_0_7_58

nginx 0.7.58 *) Feature: a "listen" directive of the mail proxy module supports IPv6. *) Feature: the "image_filter_jpeg_quality" directive. *) Feature: the "client_body_in_single_buffer" directive. *) Feature: the $request_body variable. *) Bugfix: in ngx_http_autoindex_module in file name links having a ":" symbol in the name. *) Bugfix: "make upgrade" procedure did not work; the bug had appeared in 0.7.53. Thanks to Denis F. Latypoff.
author Igor Sysoev <http://sysoev.ru>
date Mon, 18 May 2009 00:00:00 +0400
parents 6484cbba0222
children 753f505670e0
comparison
equal deleted inserted replaced
491:bb2281a3edb6 492:98143f74eb3d
9 #include <ngx_event.h> 9 #include <ngx_event.h>
10 #include <ngx_mail.h> 10 #include <ngx_mail.h>
11 11
12 12
13 static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 13 static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
14 static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); 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);
15 24
16 25
17 ngx_uint_t ngx_mail_max_module; 26 ngx_uint_t ngx_mail_max_module;
18 27
19 28
62 71
63 static char * 72 static char *
64 ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 73 ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
65 { 74 {
66 char *rv; 75 char *rv;
67 u_char *text; 76 ngx_uint_t i, m, mi, s;
68 size_t len;
69 ngx_uint_t i, a, l, m, mi, s, p, last, bind_all, done;
70 ngx_conf_t pcf; 77 ngx_conf_t pcf;
71 ngx_array_t in_ports; 78 ngx_array_t ports;
72 ngx_listening_t *ls; 79 ngx_mail_listen_t *listen;
73 ngx_mail_listen_t *mls;
74 ngx_mail_module_t *module; 80 ngx_mail_module_t *module;
75 struct sockaddr_in sin;
76 ngx_mail_in_port_t *mip;
77 ngx_mail_conf_ctx_t *ctx; 81 ngx_mail_conf_ctx_t *ctx;
78 ngx_mail_conf_in_port_t *in_port;
79 ngx_mail_conf_in_addr_t *in_addr;
80 ngx_mail_core_srv_conf_t **cscfp; 82 ngx_mail_core_srv_conf_t **cscfp;
81 ngx_mail_core_main_conf_t *cmcf; 83 ngx_mail_core_main_conf_t *cmcf;
82 84
83 if (cmd->name.data[0] == 'i') { 85 if (cmd->name.data[0] == 'i') {
84 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 86 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
215 } 217 }
216 218
217 *cf = pcf; 219 *cf = pcf;
218 220
219 221
220 if (ngx_array_init(&in_ports, cf->temp_pool, 4, 222 if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_mail_conf_port_t))
221 sizeof(ngx_mail_conf_in_port_t))
222 != NGX_OK) 223 != NGX_OK)
223 { 224 {
224 return NGX_CONF_ERROR; 225 return NGX_CONF_ERROR;
225 } 226 }
226 227
227 mls = cmcf->listen.elts; 228 listen = cmcf->listen.elts;
228 229
229 for (l = 0; l < cmcf->listen.nelts; l++) { 230 for (i = 0; i < cmcf->listen.nelts; i++) {
230 231 if (ngx_mail_add_ports(cf, &ports, &listen[i]) != NGX_OK) {
231 /* AF_INET only */
232
233 in_port = in_ports.elts;
234 for (p = 0; p < in_ports.nelts; p++) {
235 if (in_port[p].port == mls[l].port) {
236 in_port = &in_port[p];
237 goto found;
238 }
239 }
240
241 in_port = ngx_array_push(&in_ports);
242 if (in_port == NULL) {
243 return NGX_CONF_ERROR; 232 return NGX_CONF_ERROR;
244 } 233 }
245 234 }
246 in_port->port = mls[l].port; 235
247 236 return ngx_mail_optimize_servers(cf, &ports);
248 if (ngx_array_init(&in_port->addrs, cf->temp_pool, 2, 237 }
249 sizeof(ngx_mail_conf_in_addr_t)) 238
250 != NGX_OK) 239
251 { 240 static ngx_int_t
252 return NGX_CONF_ERROR; 241 ngx_mail_add_ports(ngx_conf_t *cf, ngx_array_t *ports,
253 } 242 ngx_mail_listen_t *listen)
254 243 {
255 found: 244 in_port_t p;
256 245 ngx_uint_t i;
257 in_addr = ngx_array_push(&in_port->addrs); 246 struct sockaddr *sa;
258 if (in_addr == NULL) { 247 struct sockaddr_in *sin;
259 return NGX_CONF_ERROR; 248 ngx_mail_conf_port_t *port;
260 } 249 ngx_mail_conf_addr_t *addr;
261 250 #if (NGX_HAVE_INET6)
262 in_addr->addr = mls[l].addr; 251 struct sockaddr_in6 *sin6;
263 in_addr->ctx = mls[l].ctx; 252 #endif
264 in_addr->bind = mls[l].bind; 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;
265 #if (NGX_MAIL_SSL) 311 #if (NGX_MAIL_SSL)
266 in_addr->ssl = mls[l].ssl; 312 addr->ssl = listen->ssl;
267 #endif 313 #endif
268 } 314 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
269 315 addr->ipv6only = listen->ipv6only;
270 /* optimize the lists of ports and addresses */ 316 #endif
271 317
272 /* AF_INET only */ 318 return NGX_OK;
273 319 }
274 in_port = in_ports.elts; 320
275 for (p = 0; p < in_ports.nelts; p++) { 321
276 322 static char *
277 ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, 323 ngx_mail_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports)
278 sizeof(ngx_mail_conf_in_addr_t), ngx_mail_cmp_conf_in_addrs); 324 {
279 325 ngx_uint_t i, p, last, bind_wildcard;
280 in_addr = in_port[p].addrs.elts; 326 ngx_listening_t *ls;
281 last = in_port[p].addrs.nelts; 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;
282 339
283 /* 340 /*
284 * if there is the binding to the "*:port" then we need to bind() 341 * if there is the binding to the "*:port" then we need to bind()
285 * to the "*:port" only and ignore the other bindings 342 * to the "*:port" only and ignore the other bindings
286 */ 343 */
287 344
288 if (in_addr[last - 1].addr == INADDR_ANY) { 345 if (addr[last - 1].wildcard) {
289 in_addr[last - 1].bind = 1; 346 addr[last - 1].bind = 1;
290 bind_all = 0; 347 bind_wildcard = 1;
291 348
292 } else { 349 } else {
293 bind_all = 1; 350 bind_wildcard = 0;
294 } 351 }
295 352
296 for (a = 0; a < last; /* void */ ) { 353 i = 0;
297 354
298 if (!bind_all && !in_addr[a].bind) { 355 while (i < last) {
299 a++; 356
357 if (bind_wildcard && !addr[i].bind) {
358 i++;
300 continue; 359 continue;
301 } 360 }
302 361
303 ngx_memzero(&sin, sizeof(struct sockaddr_in)); 362 ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen);
304
305 sin.sin_family = AF_INET;
306 sin.sin_addr.s_addr = in_addr[a].addr;
307 sin.sin_port = htons(in_port[p].port);
308
309 ls = ngx_create_listening(cf, &sin, sizeof(struct sockaddr_in));
310 if (ls == NULL) { 363 if (ls == NULL) {
311 return NULL; 364 return NGX_CONF_ERROR;
312 } 365 }
313 366
314 ls->addr_ntop = 1; 367 ls->addr_ntop = 1;
315 ls->handler = ngx_mail_init_connection; 368 ls->handler = ngx_mail_init_connection;
316 ls->pool_size = 256; 369 ls->pool_size = 256;
318 /* TODO: error_log directive */ 371 /* TODO: error_log directive */
319 ls->logp = &cf->cycle->new_log; 372 ls->logp = &cf->cycle->new_log;
320 ls->log.data = &ls->addr_text; 373 ls->log.data = &ls->addr_text;
321 ls->log.handler = ngx_accept_log_error; 374 ls->log.handler = ngx_accept_log_error;
322 375
323 mip = ngx_palloc(cf->pool, sizeof(ngx_mail_in_port_t)); 376 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
324 if (mip == NULL) { 377 ls->ipv6only = addr[i].ipv6only;
378 #endif
379
380 mport = ngx_palloc(cf->pool, sizeof(ngx_mail_port_t));
381 if (mport == NULL) {
325 return NGX_CONF_ERROR; 382 return NGX_CONF_ERROR;
326 } 383 }
327 384
328 ls->servers = mip; 385 ls->servers = mport;
329 386
330 in_addr = in_port[p].addrs.elts; 387 if (i == last - 1) {
331 388 mport->naddrs = last;
332 if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
333 mip->naddrs = 1;
334 done = 0;
335
336 } else if (in_port[p].addrs.nelts > 1
337 && in_addr[last - 1].addr == INADDR_ANY)
338 {
339 mip->naddrs = last;
340 done = 1;
341 389
342 } else { 390 } else {
343 mip->naddrs = 1; 391 mport->naddrs = 1;
344 done = 0; 392 i = 0;
345 } 393 }
346 394
347 #if 0 395 switch (ls->sockaddr->sa_family) {
348 ngx_log_error(NGX_LOG_ALERT, cf->log, 0, 396 #if (NGX_HAVE_INET6)
349 "%ui: %V %d %ui %ui", 397 case AF_INET6:
350 a, &ls->addr_text, in_addr[a].bind, 398 if (ngx_mail_add_addrs6(cf, mport, addr) != NGX_OK) {
351 mip->naddrs, last);
352 #endif
353
354 mip->addrs = ngx_pcalloc(cf->pool,
355 mip->naddrs * sizeof(ngx_mail_in_addr_t));
356 if (mip->addrs == NULL) {
357 return NGX_CONF_ERROR;
358 }
359
360 for (i = 0; i < mip->naddrs; i++) {
361 mip->addrs[i].addr = in_addr[i].addr;
362 mip->addrs[i].ctx = in_addr[i].ctx;
363
364 text = ngx_pnalloc(cf->pool,
365 NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1);
366 if (text == NULL) {
367 return NGX_CONF_ERROR; 399 return NGX_CONF_ERROR;
368 } 400 }
369
370 len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text,
371 NGX_INET_ADDRSTRLEN);
372
373 len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text;
374
375 mip->addrs[i].addr_text.len = len;
376 mip->addrs[i].addr_text.data = text;
377
378 #if (NGX_MAIL_SSL)
379 mip->addrs[i].ssl = in_addr[i].ssl;
380 #endif
381 }
382
383 if (done) {
384 break; 401 break;
385 } 402 #endif
386 403 default: /* AF_INET */
387 in_addr++; 404 if (ngx_mail_add_addrs(cf, mport, addr) != NGX_OK) {
388 in_port[p].addrs.elts = in_addr; 405 return NGX_CONF_ERROR;
406 }
407 break;
408 }
409
410 addr++;
389 last--; 411 last--;
390
391 a = 0;
392 } 412 }
393 } 413 }
394 414
395 return NGX_CONF_OK; 415 return NGX_CONF_OK;
396 } 416 }
397 417
398 418
399 static ngx_int_t 419 static ngx_int_t
400 ngx_mail_cmp_conf_in_addrs(const void *one, const void *two) 420 ngx_mail_add_addrs(ngx_conf_t *cf, ngx_mail_port_t *mport,
421 ngx_mail_conf_addr_t *addr)
401 { 422 {
402 ngx_mail_conf_in_addr_t *first, *second; 423 u_char *p;
403 424 size_t len;
404 first = (ngx_mail_conf_in_addr_t *) one; 425 ngx_uint_t i;
405 second = (ngx_mail_conf_in_addr_t *) two; 426 ngx_mail_in_addr_t *addrs;
406 427 struct sockaddr_in *sin;
407 if (first->addr == INADDR_ANY) { 428 u_char buf[NGX_SOCKADDR_STRLEN];
408 /* the INADDR_ANY must be the last resort, shift it to the end */ 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 */
409 return 1; 525 return 1;
410 } 526 }
411 527
412 if (first->bind && !second->bind) { 528 if (first->bind && !second->bind) {
413 /* shift explicit bind()ed addresses to the start */ 529 /* shift explicit bind()ed addresses to the start */