summaryrefslogtreecommitdiff
path: root/src/imap
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2006-04-26 08:40:02 +0000
committerJonathan Kolb <jon@b0g.us>2006-04-26 08:40:02 +0000
commitb29289f8669b359eb8d9466950c85446cac84897 (patch)
tree7f636a8460f6ed28271ec5307a4dce213505faa0 /src/imap
parent984cc0392183bbe02dad30645691f34917b8d78b (diff)
downloadnginx-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.c210
-rw-r--r--src/imap/ngx_imap.h49
-rw-r--r--src/imap/ngx_imap_core_module.c72
-rw-r--r--src/imap/ngx_imap_handler.c125
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;