Mercurial > hg > nginx-vendor-current
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 */ |