diff options
author | Igor Sysoev <igor@sysoev.ru> | 2006-04-26 08:40:02 +0000 |
---|---|---|
committer | Jonathan Kolb <jon@b0g.us> | 2006-04-26 08:40:02 +0000 |
commit | b29289f8669b359eb8d9466950c85446cac84897 (patch) | |
tree | 7f636a8460f6ed28271ec5307a4dce213505faa0 /src/imap | |
parent | 984cc0392183bbe02dad30645691f34917b8d78b (diff) | |
download | nginx-b29289f8669b359eb8d9466950c85446cac84897.tar.gz |
Changes with nginx 0.3.42 26 Apr 2006v0.3.42
*) Feature: the "bind" option of the "listen" directive in IMAP/POP3
proxy.
*) Bugfix: if the same capture in the "rewrite" directive was used more
then once.
*) Bugfix: the $sent_http_content_type, $sent_http_content_length,
$sent_http_last_modified, $sent_http_connection,
$sent_http_keep_alive, and $sent_http_transfer_encoding variables
were not written to access log.
*) Bugfix: the $sent_http_cache_control returned value of the single
"Cache-Control" response header line.
Diffstat (limited to 'src/imap')
-rw-r--r-- | src/imap/ngx_imap.c | 210 | ||||
-rw-r--r-- | src/imap/ngx_imap.h | 49 | ||||
-rw-r--r-- | src/imap/ngx_imap_core_module.c | 72 | ||||
-rw-r--r-- | src/imap/ngx_imap_handler.c | 125 |
4 files changed, 396 insertions, 60 deletions
diff --git a/src/imap/ngx_imap.c b/src/imap/ngx_imap.c index 2b768ddfb..77b605620 100644 --- a/src/imap/ngx_imap.c +++ b/src/imap/ngx_imap.c @@ -11,6 +11,8 @@ static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static int ngx_libc_cdecl ngx_imap_cmp_conf_in_addrs(const void *one, + const void *two); ngx_uint_t ngx_imap_max_module; @@ -56,10 +58,18 @@ static char * ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_uint_t m, mi, s; + u_char *text; + size_t len; + ngx_uint_t i, a, l, m, mi, s, p, last, bind_all, done; ngx_conf_t pcf; + ngx_array_t in_ports; + ngx_listening_t *ls; + ngx_imap_listen_t *imls; ngx_imap_module_t *module; + ngx_imap_in_port_t *imip; ngx_imap_conf_ctx_t *ctx; + ngx_imap_conf_in_port_t *in_port; + ngx_imap_conf_in_addr_t *in_addr; ngx_imap_core_srv_conf_t **cscfp; ngx_imap_core_main_conf_t *cmcf; @@ -191,5 +201,203 @@ ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) *cf = pcf; + + if (ngx_array_init(&in_ports, cf->temp_pool, 4, + sizeof(ngx_imap_conf_in_port_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + imls = cmcf->listen.elts; + + for (l = 0; l < cmcf->listen.nelts; l++) { + + /* AF_INET only */ + + in_port = in_ports.elts; + for (p = 0; p < in_ports.nelts; p++) { + if (in_port[p].port == imls[l].port) { + in_port = &in_port[p]; + goto found; + } + } + + in_port = ngx_array_push(&in_ports); + if (in_port == NULL) { + return NGX_CONF_ERROR; + } + + in_port->port = imls[l].port; + + if (ngx_array_init(&in_port->addrs, cf->temp_pool, 2, + sizeof(ngx_imap_conf_in_addr_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + found: + + in_addr = ngx_array_push(&in_port->addrs); + if (in_addr == NULL) { + return NGX_CONF_ERROR; + } + + in_addr->addr = imls[l].addr; + in_addr->ctx = imls[l].ctx; + in_addr->bind = imls[l].bind; + } + + /* optimize the lists of ports and addresses */ + + /* AF_INET only */ + + in_port = in_ports.elts; + for (p = 0; p < in_ports.nelts; p++) { + + ngx_qsort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, + sizeof(ngx_imap_conf_in_addr_t), ngx_imap_cmp_conf_in_addrs); + + in_addr = in_port[p].addrs.elts; + last = in_port[p].addrs.nelts; + + /* + * if there is the binding to the "*:port" then we need to bind() + * to the "*:port" only and ignore the other bindings + */ + + if (in_addr[last - 1].addr == INADDR_ANY) { + in_addr[last - 1].bind = 1; + bind_all = 0; + + } else { + bind_all = 1; + } + + for (a = 0; a < last; /* void */ ) { + + if (!bind_all && !in_addr[a].bind) { + a++; + continue; + } + + ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, + in_port[p].port); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ls->backlog = -1; + ls->rcvbuf = -1; + ls->sndbuf = -1; + + ls->addr_ntop = 1; + ls->handler = ngx_imap_init_connection; + ls->pool_size = 256; + + /* STUB */ + ls->log = *cf->cycle->new_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + /**/ + + imip = ngx_palloc(cf->pool, sizeof(ngx_imap_in_port_t)); + if (imip == NULL) { + return NGX_CONF_ERROR; + } + + ls->servers = imip; + + in_addr = in_port[p].addrs.elts; + + if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { + imip->naddrs = 1; + done = 0; + + } else if (in_port[p].addrs.nelts > 1 + && in_addr[last - 1].addr == INADDR_ANY) + { + imip->naddrs = last; + done = 1; + + } else { + imip->naddrs = 1; + done = 0; + } + +#if 0 + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, + "%ui: %V %d %ui %ui", + a, &ls->addr_text, in_addr[a].bind, + imip->naddrs, last); +#endif + + imip->addrs = ngx_pcalloc(cf->pool, + imip->naddrs * sizeof(ngx_imap_in_addr_t)); + if (imip->addrs == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < imip->naddrs; i++) { + imip->addrs[i].addr = in_addr[i].addr; + imip->addrs[i].ctx = in_addr[i].ctx; + + text = ngx_palloc(cf->pool, + INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); + if (text == NULL) { + return NGX_CONF_ERROR; + } + + len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text, + INET_ADDRSTRLEN); + + len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text; + + imip->addrs[i].addr_text.len = len; + imip->addrs[i].addr_text.data = text; + } + + if (done) { + break; + } + + in_addr++; + in_port[p].addrs.elts = in_addr; + last--; + + a = 0; + } + } + return NGX_CONF_OK; } + + +static int ngx_libc_cdecl +ngx_imap_cmp_conf_in_addrs(const void *one, const void *two) +{ + ngx_imap_conf_in_addr_t *first, *second; + + first = (ngx_imap_conf_in_addr_t *) one; + second = (ngx_imap_conf_in_addr_t *) two; + + if (first->addr == INADDR_ANY) { + /* the INADDR_ANY must be the last resort, shift it to the end */ + return 1; + } + + if (first->bind && !second->bind) { + /* shift explicit bind()ed addresses to the start */ + return -1; + } + + if (!first->bind && second->bind) { + /* shift explicit bind()ed addresses to the start */ + return 1; + } + + /* do not sort by default */ + + return 0; +} diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h index 90375bfb2..e4928be55 100644 --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -26,7 +26,46 @@ typedef struct { typedef struct { - ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ + in_addr_t addr; + in_port_t port; + int family; + + /* server ctx */ + ngx_imap_conf_ctx_t *ctx; + + unsigned bind:1; +} ngx_imap_listen_t; + + +typedef struct { + in_addr_t addr; + ngx_imap_conf_ctx_t *ctx; + ngx_str_t addr_text; +} ngx_imap_in_addr_t; + + +typedef struct { + ngx_imap_in_addr_t *addrs; /* array of ngx_imap_in_addr_t */ + ngx_uint_t naddrs; +} ngx_imap_in_port_t; + + +typedef struct { + in_port_t port; + ngx_array_t addrs; /* array of ngx_imap_conf_in_addr_t */ +} ngx_imap_conf_in_port_t; + + +typedef struct { + in_addr_t addr; + ngx_imap_conf_ctx_t *ctx; + unsigned bind:1; +} ngx_imap_conf_in_addr_t; + + +typedef struct { + ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ + ngx_array_t listen; /* ngx_imap_listen_t */ } ngx_imap_core_main_conf_t; @@ -52,7 +91,7 @@ typedef struct { ngx_array_t imap_capabilities; /* server ctx */ - ngx_imap_conf_ctx_t *ctx; + ngx_imap_conf_ctx_t *ctx; } ngx_imap_core_srv_conf_t; @@ -109,6 +148,7 @@ typedef struct { unsigned quoted:1; unsigned backslash:1; unsigned no_sync_literal:1; + unsigned starttls:1; ngx_str_t login; ngx_str_t passwd; @@ -116,6 +156,8 @@ typedef struct { ngx_str_t tag; ngx_str_t tagged_line; + ngx_str_t *addr_text; + ngx_uint_t command; ngx_array_t args; @@ -184,6 +226,9 @@ typedef struct { (s)->main_conf[module.ctx_index] #define ngx_imap_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index] +#define ngx_imap_conf_get_module_main_conf(cf, module) \ + ((ngx_imap_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] + void ngx_imap_init_connection(ngx_connection_t *c); void ngx_imap_send(ngx_event_t *wev); diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c index c454f1936..c76ad6c67 100644 --- a/src/imap/ngx_imap_core_module.c +++ b/src/imap/ngx_imap_core_module.c @@ -55,7 +55,7 @@ static ngx_command_t ngx_imap_core_commands[] = { NULL }, { ngx_string("listen"), - NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + NGX_IMAP_SRV_CONF|NGX_CONF_TAKE12, ngx_imap_core_listen, 0, 0, @@ -143,7 +143,14 @@ ngx_imap_core_create_main_conf(ngx_conf_t *cf) } if (ngx_array_init(&cmcf->servers, cf->pool, 4, - sizeof(ngx_imap_core_srv_conf_t *)) == NGX_ERROR) + sizeof(ngx_imap_core_srv_conf_t *)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_imap_listen_t)) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -419,12 +426,14 @@ ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) static char * ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - char *err; - ngx_str_t *value; - in_addr_t in_addr; - struct hostent *h; - ngx_listening_t *ls; - ngx_inet_upstream_t inet_upstream; + char *err; + ngx_str_t *value; + in_addr_t in_addr; + ngx_uint_t i; + struct hostent *h; + ngx_imap_listen_t *imls; + ngx_inet_upstream_t inet_upstream; + ngx_imap_core_main_conf_t *cmcf; value = cf->args->elts; @@ -469,29 +478,46 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) in_addr = INADDR_ANY; } + cmcf = ngx_imap_conf_get_module_main_conf(cf, ngx_imap_core_module); + + imls = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts; i++) { - ls = ngx_listening_inet_stream_socket(cf, in_addr, inet_upstream.port); - if (ls == NULL) { + if (imls[i].addr != in_addr || imls[i].port != inet_upstream.port) { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", + &inet_upstream.url); + return NGX_CONF_ERROR; + } + + imls = ngx_array_push(&cmcf->listen); + if (imls == NULL) { return NGX_CONF_ERROR; } - ls->backlog = -1; - ls->rcvbuf = -1; - ls->sndbuf = -1; + ngx_memzero(imls, sizeof(ngx_imap_listen_t)); - ls->addr_ntop = 1; - ls->handler = ngx_imap_init_connection; - ls->pool_size = 256; + imls->addr = in_addr; + imls->port = inet_upstream.port; + imls->family = AF_INET; + imls->ctx = cf->ctx; - ls->ctx = cf->ctx; + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } - /* STUB */ - ls->log = *cf->cycle->new_log; - ls->log.data = &ls->addr_text; - ls->log.handler = ngx_accept_log_error; - /**/ + if (ngx_strcmp(value[2].data, "bind") == 0) { + imls->bind = 1; + return NGX_CONF_OK; + } - return NGX_CONF_OK; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the invalid \"%V\" parameter", &value[2]); + return NGX_CONF_ERROR; } diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c index f90b96880..4a4c2c7cd 100644 --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -44,35 +44,103 @@ static u_char imap_invalid_command[] = "BAD invalid command" CRLF; void ngx_imap_init_connection(ngx_connection_t *c) { - ngx_imap_log_ctx_t *lctx; + in_addr_t in_addr; + socklen_t len; + ngx_uint_t i; + struct sockaddr_in sin; + ngx_imap_log_ctx_t *ctx; + ngx_imap_in_port_t *imip; + ngx_imap_in_addr_t *imia; + ngx_imap_session_t *s; #if (NGX_IMAP_SSL) - ngx_imap_conf_ctx_t *ctx; ngx_imap_ssl_conf_t *sslcf; #endif + + /* find the server configuration for the address:port */ + + /* AF_INET only */ + + imip = c->listening->servers; + imia = imip->addrs; + + i = 0; + + if (imip->naddrs > 1) { + + /* + * There are several addresses on this port and one of them + * is the "*:port" wildcard so getsockname() is needed to determine + * the server address. + * + * AcceptEx() already gave this address. + */ + +#if (NGX_WIN32) + if (c->local_sockaddr) { + in_addr = + ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; + + } else +#endif + { + len = sizeof(struct sockaddr_in); + if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { + ngx_connection_error(c, ngx_socket_errno, + "getsockname() failed"); + ngx_imap_close_connection(c); + return; + } + + in_addr = sin.sin_addr.s_addr; + } + + /* the last address is "*" */ + + for ( /* void */ ; i < imip->naddrs - 1; i++) { + if (in_addr == imia[i].addr) { + break; + } + } + } + + + s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)); + if (s == NULL) { + ngx_imap_close_connection(c); + return; + } + + s->main_conf = imia[i].ctx->main_conf; + s->srv_conf = imia[i].ctx->srv_conf; + + s->addr_text = &imia[i].addr_text; + + c->data = s; + s->connection = c; + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V", - c->number, &c->addr_text, &c->listening->addr_text); + c->number, &c->addr_text, s->addr_text); - lctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t)); - if (lctx == NULL) { + ctx = ngx_palloc(c->pool, sizeof(ngx_imap_log_ctx_t)); + if (ctx == NULL) { ngx_imap_close_connection(c); return; } - lctx->client = &c->addr_text; - lctx->session = NULL; + ctx->client = &c->addr_text; + ctx->session = s; c->log->connection = c->number; c->log->handler = ngx_imap_log_error; - c->log->data = lctx; + c->log->data = ctx; c->log->action = "sending client greeting line"; c->log_error = NGX_ERROR_INFO; #if (NGX_IMAP_SSL) - ctx = c->ctx; - sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module); + sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module); if (sslcf->enable) { ngx_imap_ssl_init_connection(&sslcf->ssl, c); @@ -96,6 +164,7 @@ ngx_imap_starttls_handler(ngx_event_t *rev) c = rev->data; s = c->data; + s->starttls = 1; c->log->action = "in starttls state"; @@ -108,7 +177,7 @@ ngx_imap_starttls_handler(ngx_event_t *rev) static void ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) { - ngx_imap_conf_ctx_t *ctx; + ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { @@ -118,8 +187,9 @@ ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) if (ngx_ssl_handshake(c) == NGX_AGAIN) { - ctx = c->ctx; - cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + s = c->data; + + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); ngx_add_timer(c->read, cscf->timeout); @@ -135,9 +205,13 @@ ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c) { + ngx_imap_session_t *s; + if (c->ssl->handshaked) { - if (c->data) { + s = c->data; + + if (s->starttls) { c->read->handler = ngx_imap_init_protocol; c->write->handler = ngx_imap_send; @@ -160,24 +234,14 @@ static void ngx_imap_init_session(ngx_connection_t *c) { ngx_imap_session_t *s; - ngx_imap_log_ctx_t *lctx; - ngx_imap_conf_ctx_t *ctx; ngx_imap_core_srv_conf_t *cscf; c->read->handler = ngx_imap_init_protocol; c->write->handler = ngx_imap_send; - s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)); - if (s == NULL) { - ngx_imap_close_connection(c); - return; - } - - ctx = c->ctx; - cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + s = c->data; - c->data = s; - s->connection = c; + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); s->protocol = cscf->protocol; @@ -187,14 +251,8 @@ ngx_imap_init_session(ngx_connection_t *c) return; } - s->main_conf = ctx->main_conf; - s->srv_conf = ctx->srv_conf; - s->out = greetings[s->protocol]; - lctx = c->log->data; - lctx->session = s; - ngx_add_timer(c->read, cscf->timeout); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { @@ -896,8 +954,7 @@ ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len) return p; } - p = ngx_snprintf(buf, len, ", server: %V", - &s->connection->listening->addr_text); + p = ngx_snprintf(buf, len, ", server: %V", s->addr_text); len -= p - buf; buf = p; |