diff options
-rw-r--r-- | auto/sources | 1 | ||||
-rw-r--r-- | src/core/ngx_connection.h | 2 | ||||
-rw-r--r-- | src/event/ngx_event_accept.c | 53 | ||||
-rw-r--r-- | src/event/ngx_event_connect.h | 18 | ||||
-rw-r--r-- | src/http/modules/proxy/ngx_http_proxy_handler.c | 5 | ||||
-rw-r--r-- | src/http/ngx_http.c | 4 | ||||
-rw-r--r-- | src/http/ngx_http_parse.c | 10 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 15 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 2 | ||||
-rw-r--r-- | src/imap/ngx_imap.c | 1 | ||||
-rw-r--r-- | src/imap/ngx_imap.h | 59 | ||||
-rw-r--r-- | src/imap/ngx_imap_handler.c | 48 | ||||
-rw-r--r-- | src/imap/ngx_imap_parse.c | 152 | ||||
-rw-r--r-- | src/imap/ngx_imap_proxy.c | 238 | ||||
-rw-r--r-- | src/os/unix/ngx_send.c | 2 | ||||
-rw-r--r-- | src/os/win32/ngx_win32_config.h | 1 |
16 files changed, 498 insertions, 113 deletions
diff --git a/auto/sources b/auto/sources index 79a48e88c..d1bb2d8e6 100644 --- a/auto/sources +++ b/auto/sources @@ -299,4 +299,5 @@ IMAP_DEPS="src/imap/ngx_imap.h" IMAP_MODULE=ngx_imap_module IMAP_SRCS="src/imap/ngx_imap.c \ src/imap/ngx_imap_handler.c \ + src/imap/ngx_imap_parse.c \ src/imap/ngx_imap_proxy.c" diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index b84695685..ed5d53dc2 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -49,6 +49,8 @@ typedef struct { #if (HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; #endif + + unsigned addr_ntop:1; } ngx_listening_t; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index d84d8c542..10f24a6ad 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,7 @@ typedef struct { } ngx_accept_log_ctx_t; +static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log); static size_t ngx_accept_log_error(void *data, char *buf, size_t len); @@ -138,11 +139,7 @@ void ngx_event_accept(ngx_event_t *ev) "closing the connection", ls->listening->addr_text.data, s, ecf->connections); - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, - ngx_close_socket_n "failed"); - } - + ngx_close_accepted_socket(s, log); ngx_destroy_pool(pool); return; } @@ -155,11 +152,7 @@ void ngx_event_accept(ngx_event_t *ev) ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, ngx_blocking_n " failed"); - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - + ngx_close_accepted_socket(s, log); ngx_destroy_pool(pool); return; } @@ -171,11 +164,7 @@ void ngx_event_accept(ngx_event_t *ev) ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, ngx_nonblocking_n " failed"); - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - + ngx_close_accepted_socket(s, log); ngx_destroy_pool(pool); return; } @@ -286,6 +275,25 @@ void ngx_event_accept(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "accept: fd:%d c:%d", s, c->number); + if (c->listening->addr_ntop) { + c->addr_text.data = ngx_palloc(c->pool, + c->listening->addr_text_max_len); + if (c->addr_text.data == NULL) { + ngx_close_accepted_socket(s, log); + ngx_destroy_pool(pool); + return; + } + + c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, + c->addr_text.data, + c->listening->addr_text_max_len); + if (c->addr_text.len == 0) { + ngx_close_accepted_socket(s, log); + ngx_destroy_pool(pool); + return; + } + } + #if (NGX_DEBUG) { @@ -307,11 +315,7 @@ void ngx_event_accept(ngx_event_t *ev) if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { if (ngx_add_conn(c) == NGX_ERROR) { - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - + ngx_close_accepted_socket(s, log); ngx_destroy_pool(pool); return; } @@ -440,6 +444,15 @@ ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle) } +static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log) +{ + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } +} + + static size_t ngx_accept_log_error(void *data, char *buf, size_t len) { ngx_accept_log_ctx_t *ctx = data; diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h index 01299f12b..8a3e17fdf 100644 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -13,20 +13,20 @@ typedef struct { in_addr_t addr; ngx_str_t host; - int port; + in_port_t port; ngx_str_t addr_port_text; - int fails; + ngx_int_t fails; time_t accessed; } ngx_peer_t; typedef struct { - int current; - int number; - int max_fails; - int fail_timeout; - int last_cached; + ngx_int_t current; + ngx_int_t number; + ngx_int_t max_fails; + ngx_int_t fail_timeout; + ngx_int_t last_cached; /* ngx_mutex_t *mutex; */ ngx_connection_t **cached; @@ -37,8 +37,8 @@ typedef struct { typedef struct { ngx_peers_t *peers; - int cur_peer; - int tries; + ngx_int_t cur_peer; + ngx_int_t tries; ngx_connection_t *connection; #if (NGX_THREADS) diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c index af9760c2e..f057d3c98 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -1227,7 +1227,8 @@ static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, u->port_text.len = &url->data[i] - u->port_text.data; if (u->port_text.len > 0) { - u->port = ngx_atoi(u->port_text.data, u->port_text.len); + u->port = (in_port_t) ngx_atoi(u->port_text.data, + u->port_text.len); if (u->port > 0) { if (u->port == 80) { @@ -1263,7 +1264,7 @@ static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, u->port_text.len = &url->data[i] - u->port_text.data; if (u->port_text.len > 0) { - u->port = ngx_atoi(u->port_text.data, u->port_text.len); + u->port = (in_port_t) ngx_atoi(u->port_text.data, u->port_text.len); if (u->port > 0) { u->port = htons(u->port); return NULL; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index d02b2503a..391bd1bf8 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -54,10 +54,9 @@ ngx_module_t ngx_http_module = { static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + char *rv; ngx_uint_t mi, m, s, l, p, a, n; ngx_uint_t port_found, addr_found, virtual_names; - char *rv; - struct sockaddr_in *addr_in; ngx_conf_t pcf; ngx_array_t in_ports; ngx_listening_t *ls; @@ -514,6 +513,7 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->nonblocking = 0; #endif #endif + ls->addr_ntop = 1; ls->handler = ngx_http_init_connection; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 8136f31d3..dd2d3749a 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -65,19 +65,19 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r) if (r->method_end - m == 3) { - if (*m == 'G' && *(m + 1) == 'E' && *(m + 2) == 'T') { + if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { r->method = NGX_HTTP_GET; } } else if (r->method_end - m == 4) { - if (*m == 'P' && *(m + 1) == 'O' - && *(m + 2) == 'T' && *(m + 3) == 'T') + if (m[0] == 'P' && m[1] == 'O' + && m[2] == 'T' && m[3] == 'T') { r->method = NGX_HTTP_POST; - } else if (*m == 'H' && *(m + 1) == 'E' - && *(m + 2) == 'A' && *(m + 3) == 'D') + } else if (m[0] == 'H' && m[1] == 'E' + && m[2] == 'A' && m[3] == 'D') { r->method = NGX_HTTP_HEAD; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index dcf53d746..a1081af12 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -97,21 +97,6 @@ void ngx_http_init_connection(ngx_connection_t *c) ngx_event_t *rev; ngx_http_log_ctx_t *ctx; - c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len); - if (c->addr_text.data == NULL) { - ngx_http_close_connection(c); - return; - } - - c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, - c->addr_text.data, - c->listening->addr_text_max_len); - - if (c->addr_text.len == 0) { - ngx_http_close_connection(c); - return; - } - if (!(ctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) { ngx_http_close_connection(c); return; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index abd52bc5e..cc0cbbf5e 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -311,7 +311,7 @@ struct ngx_http_request_s { ngx_uint_t headers_n; /* used to parse HTTP headers */ - ngx_int_t state; + ngx_uint_t state; u_char *uri_start; u_char *uri_end; u_char *uri_ext; diff --git a/src/imap/ngx_imap.c b/src/imap/ngx_imap.c index 13855f17d..eb12b6790 100644 --- a/src/imap/ngx_imap.c +++ b/src/imap/ngx_imap.c @@ -50,6 +50,7 @@ static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } ls->backlog = -1; + ls->addr_ntop = 1; ls->handler = ngx_imap_init_connection; ls->pool_size = 16384; /* ls->post_accept_timeout = 0; */ diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h index 6f5307d3d..d5adc184e 100644 --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -4,40 +4,63 @@ #include <ngx_config.h> #include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_event_connect.h> typedef struct { - ngx_connection_t *connection; + ngx_peer_connection_t upstream; - ngx_buf_t *downstream_buffer; - ngx_buf_t *upstream_buffer; + ngx_buf_t *buffer; } ngx_imap_proxy_ctx_t; typedef struct { - uint32_t signature; /* "IMAP" */ + uint32_t signature; /* "IMAP" */ - ngx_connection_t *connection; - ngx_imap_proxy_ctx_t *proxy; + ngx_connection_t *connection; + ngx_buf_t *buffer; + + ngx_imap_proxy_ctx_t *proxy; + + ngx_uint_t command; + ngx_array_t args; + + /* used to parse IMAP/POP3 command */ + + ngx_uint_t state; + u_char *arg_start; + u_char *arg_end; } ngx_imap_session_t; -#define NGX_POP3_USER 1 -#define NGX_POP3_PASS 2 -#define NGX_POP3_APOP 3 -#define NGX_POP3_STAT 4 -#define NGX_POP3_LIST 5 -#define NGX_POP3_RETR 6 -#define NGX_POP3_DELE 7 -#define NGX_POP3_NOOP 8 -#define NGX_POP3_RSET 9 -#define NGX_POP3_TOP 10 -#define NGX_POP3_UIDL 11 -#define NGX_POP3_QUIT 12 +#define NGX_POP3_USER 1 +#define NGX_POP3_PASS 2 +#define NGX_POP3_APOP 3 +#define NGX_POP3_STAT 4 +#define NGX_POP3_LIST 5 +#define NGX_POP3_RETR 6 +#define NGX_POP3_DELE 7 +#define NGX_POP3_NOOP 8 +#define NGX_POP3_RSET 9 +#define NGX_POP3_TOP 10 +#define NGX_POP3_UIDL 11 +#define NGX_POP3_QUIT 12 + + +#define NGX_IMAP_PARSE_INVALID_COMMAND 10 + + +#define NGX_IMAP_PROXY_INVALID 10 +#define NGX_IMAP_PROXY_ERROR 11 void ngx_imap_init_connection(ngx_connection_t *c); void ngx_imap_close_connection(ngx_connection_t *c); +void ngx_imap_proxy_init(ngx_imap_session_t *s); + +ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s); + #endif /* _NGX_IMAP_H_INCLUDED_ */ diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c index 61c59c98d..55808fac4 100644 --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -6,7 +6,7 @@ #include <nginx.h> -static void ngx_imap_auth_state(ngx_event_t *rev); +static void ngx_imap_init_session(ngx_event_t *rev); static char pop3_greeting[] = "+OK " NGINX_VER " ready" CRLF; @@ -15,36 +15,66 @@ static char imap_greeting[] = "* OK " NGINX_VER " ready" CRLF; void ngx_imap_init_connection(ngx_connection_t *c) { - ngx_int_t n; + char *greeting; + ssize_t size; + ngx_int_t n; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection"); c->log_error = NGX_ERROR_INFO; - n = ngx_send(c, pop3_greeting, sizeof(pop3_greeting) - 1); + greeting = pop3_greeting; + size = sizeof(pop3_greeting) - 1; - if (n == NGX_ERROR) { + n = ngx_send(c, greeting, size); + + if (n < size) { + /* + * we treat the incomplete sending as NGX_ERROR + * because it is very strange here + */ ngx_imap_close_connection(c); return; } - c->read->event_handler = ngx_imap_auth_state; + c->read->event_handler = ngx_imap_init_session; + + ngx_add_timer(c->read, /* STUB */ 60000); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { ngx_imap_close_connection(c); - return; } } -static void ngx_imap_auth_state(ngx_event_t *rev) +static void ngx_imap_init_session(ngx_event_t *rev) { - ngx_connection_t *c; + ngx_connection_t *c; + ngx_imap_session_t *s; c = rev->data; - ngx_imap_close_connection(c); + if (!(s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)))) { + ngx_imap_close_connection(c); + return; + } + + c->data = s; + s->connection = c; + + if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { + ngx_imap_close_connection(s->connection); + return; + } + + s->buffer = ngx_create_temp_buf(s->connection->pool, /* STUB */ 4096); + if (s->buffer == NULL) { + ngx_imap_close_connection(s->connection); + return; + } + + ngx_imap_proxy_init(s); } diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c index 08ff86355..e29791d73 100644 --- a/src/imap/ngx_imap_parse.c +++ b/src/imap/ngx_imap_parse.c @@ -5,49 +5,75 @@ #include <ngx_imap.h> -ngx_int_t ngx_pop3_parse_command(ngx_imap_request_t *r) +ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s) { - u_char ch, *p, *c; + u_char ch, *p, *c; + ngx_str_t *arg; enum { sw_start = 0, + sw_spaces_before_argument, + sw_argument, + sw_almost_done, sw_done } state; - while (p < r->buf->last && state < sw_done) { + state = s->state; + p = s->buffer->pos; + + while (p < s->buffer->last && state < sw_done) { ch = *p++; switch (state) { - /* POP3 commands */ + /* POP3 command */ + case sw_start: - if (ch == ' ') { - c = r->buf->start; + if (ch == ' ' || ch == CR || ch == LF) { + c = s->buffer->start; - if (p - 1 - m == 4) { + if (p - 1 - c == 4) { - if (*c == 'U' && *(c + 1) == 'S' - && *(c + 2) == 'E' && *(c + 3) == 'R') + if (c[0] == 'U' && c[1] == 'S' + && c[2] == 'E' && c[3] == 'R') { - r->command = NGX_POP3_USER; + s->command = NGX_POP3_USER; - } else if (*c == 'P' && *(c + 1) == 'A' - && *(c + 2) == 'A' && *(c + 3) == 'S') + } else if (c[0] == 'P' && c[1] == 'A' + && c[2] == 'A' && c[3] == 'S') { - r->method = NGX_POP3_PASS; + s->command = NGX_POP3_PASS; - } else if (*c == 'Q' && *(c + 1) == 'U' - && *(c + 2) == 'I' && *(c + 3) == 'T') + } else if (c[0] == 'Q' && c[1] == 'U' + && c[2] == 'I' && c[3] == 'T') { - r->method = NGX_POP3_QUIT; + s->command = NGX_POP3_QUIT; - } else if (*c == 'N' && *(c + 1) == 'O' - && *(c + 2) == 'O' && *(c + 3) == 'P') +#if 0 + } else if (c[0] == 'N' && c[1] == 'O' + && c[2] == 'O' && c[3] == 'P') { - r->method = NGX_POP3_NOOP; + s->command = NGX_POP3_NOOP; +#endif + + } else { + return NGX_IMAP_PARSE_INVALID_COMMAND; } + + } else { + return NGX_IMAP_PARSE_INVALID_COMMAND; } - state = sw_spaces_before_arg; + switch (ch) { + case ' ': + state = sw_spaces_before_argument; + break; + case CR: + state = sw_almost_done; + break; + case LF: + state = sw_done; + break; + } break; } @@ -56,7 +82,72 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_request_t *r) } break; - } + + /* the spaces before the argument */ + case sw_spaces_before_argument: + switch (ch) { + case ' ': + break; + case CR: + state = sw_almost_done; + s->arg_end = p - 1; + break; + case LF: + state = sw_done; + s->arg_end = p - 1; + break; + default: + if (s->args.nelts > 2) { + return NGX_IMAP_PARSE_INVALID_COMMAND; + } + + state = sw_argument; + s->arg_start = p - 1; + break; + } + break; + + /* the argument */ + case sw_argument: + switch (ch) { + case ' ': + case CR: + case LF: + if (!(arg = ngx_array_push(&s->args))) { + return NGX_ERROR; + } + arg->len = p - s->arg_start; + arg->data = s->arg_start; + s->arg_start = NULL; + + switch (ch) { + case ' ': + state = sw_spaces_before_argument; + break; + case CR: + state = sw_almost_done; + break; + case LF: + state = sw_done; + break; + } + break; + + default: + break; + } + break; + + /* end of request line */ + case sw_almost_done: + switch (ch) { + case LF: + state = sw_done; + break; + default: + return NGX_IMAP_PARSE_INVALID_COMMAND; + } + break; /* suppress warning */ case sw_done: @@ -64,5 +155,22 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_request_t *r) } } - return NGX_OK; + s->buffer->pos = p; + + if (state == sw_done) { + if (s->arg_start) { + if (!(arg = ngx_array_push(&s->args))) { + return NGX_ERROR; + } + arg->len = s->arg_end - s->arg_start; + arg->data = s->arg_start; + s->arg_start = NULL; + } + + return NGX_OK; + + } else { + s->state = state; + return NGX_AGAIN; + } } diff --git a/src/imap/ngx_imap_proxy.c b/src/imap/ngx_imap_proxy.c index f856159ff..6a915f701 100644 --- a/src/imap/ngx_imap_proxy.c +++ b/src/imap/ngx_imap_proxy.c @@ -2,14 +2,200 @@ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> +#include <ngx_event_connect.h> #include <ngx_imap.h> +static void ngx_imap_proxy_block_read(ngx_event_t *rev); +static void ngx_imap_proxy_greeting_handler(ngx_event_t *rev); +static void ngx_imap_proxy_init_handler(ngx_event_t *wev); +static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev); +static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s); +static void ngx_imap_proxy_handler(ngx_event_t *ev); static void ngx_imap_proxy_close_session(ngx_imap_session_t *s); -void ngx_imap_proxy_handler(ngx_event_t *ev) +void ngx_imap_proxy_init(ngx_imap_session_t *s) { + ngx_int_t rc; + ngx_peers_t *peers; + ngx_imap_proxy_ctx_t *p; + + if (!(p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t)))) { + ngx_imap_close_connection(s->connection); + return; + } + + s->proxy = p; + + /**/ + + if (!(peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t)))) { + ngx_imap_close_connection(s->connection); + return; + } + + p->upstream.peers = peers; + p->upstream.log = s->connection->log; + p->upstream.log_error = NGX_ERROR_ERR; + + peers->number = 1; + peers->max_fails = 1; + peers->peers[0].addr = inet_addr("81.19.69.70"); + peers->peers[0].addr_port_text.len = sizeof("81.19.69.70:110") - 1; + peers->peers[0].addr_port_text.data = "81.19.69.70:110"; + peers->peers[0].port = htons(110); + + rc = ngx_event_connect_peer(&p->upstream); + + if (rc == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + p->upstream.connection->data = s; + p->upstream.connection->pool = s->connection->pool; + + s->connection->read->event_handler = ngx_imap_proxy_block_read; + p->upstream.connection->read->event_handler = + ngx_imap_proxy_greeting_handler; + p->upstream.connection->write->event_handler = ngx_imap_proxy_dummy_handler; +} + + +static void ngx_imap_proxy_block_read(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_imap_session_t *s; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy block read"); + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + c = rev->data; + s = c->data; + + ngx_imap_proxy_close_session(s); + } +} + + +static void ngx_imap_proxy_greeting_handler(ngx_event_t *rev) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_connection_t *c; + ngx_imap_session_t *s; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, + "imap proxy greeting handler"); + + c = rev->data; + s = c->data; + + if (s->proxy->buffer == NULL) { + s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096); + if (s->proxy->buffer == NULL) { + ngx_imap_proxy_close_session(s); + return; + } + } + + rc = ngx_imap_proxy_read_response(s); + + if (rc == NGX_AGAIN) { + return; + } + + if (rc == NGX_OK) { + s->connection->read->event_handler = ngx_imap_proxy_handler; + s->connection->write->event_handler = ngx_imap_proxy_handler; + rev->event_handler = ngx_imap_proxy_handler; + c->write->event_handler = ngx_imap_proxy_handler; + + b = s->proxy->buffer; + b->pos = b->start; + b->last = b->start; + + if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + if (s->connection->read->ready) { + ngx_imap_proxy_handler(s->connection->read); + } + + return; + } + + /* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */ + ngx_imap_proxy_close_session(s); +} + + +static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); +} + + +static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s) +{ + u_char *p; + ssize_t n; + ngx_buf_t *b; + + b = s->proxy->buffer; + + n = ngx_recv(s->proxy->upstream.connection, b->last, b->end - b->last); + + if (n == NGX_ERROR || n == 0) { + return NGX_ERROR; + } + + if (n == NGX_AGAIN) { + return NGX_AGAIN; + } + + b->last += n; + + if (b->last - b->pos < 5) { + return NGX_AGAIN; + } + + if (*(b->last - 2) != CR || *(b->last - 1) != LF) { + if (b->last == b->end) { + *(b->last - 1) = '\0'; + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "upstream sent too long response line: \"%s\"", + b->pos); + return NGX_IMAP_PROXY_INVALID; + } + + return NGX_AGAIN; + } + + p = b->pos; + + if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') { + return NGX_OK; + } + + if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') { + return NGX_IMAP_PROXY_ERROR; + } + + *(b->last - 2) = '\0'; + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "upstream sent invalid greeting line: \"%s\"", p); + + return NGX_IMAP_PROXY_INVALID; +} + + +static void ngx_imap_proxy_handler(ngx_event_t *ev) +{ + size_t size; ssize_t n; ngx_buf_t *b; ngx_uint_t data, do_write; @@ -21,23 +207,30 @@ void ngx_imap_proxy_handler(ngx_event_t *ev) if (c == s->connection) { src = c; - dst = s->proxy->connection; - b = s->proxy->downstream_buffer; + dst = s->proxy->upstream.connection; + b = s->buffer; } else { - src = s->proxy->connection; - dst = c; - b = s->proxy->upstream_buffer; + src = c; + dst = s->connection; + b = s->proxy->buffer; } do_write = ev->write ? 1 : 0; + ngx_log_debug3(NGX_LOG_DEBUG_IMAP, ev->log, 0, + "imap proxy handler: %d, #%d > #%d", + do_write, src->fd, dst->fd); + do { data = 0; if (do_write == 1) { - if (dst->write->ready && b->pos < b->last) { - n = ngx_send(dst, b->pos, b->last - b->pos); + + size = b->last - b->pos; + + if (dst->write->ready && size) { + n = ngx_send(dst, b->pos, size); if (n == NGX_ERROR) { ngx_imap_proxy_close_session(s); @@ -53,11 +246,23 @@ void ngx_imap_proxy_handler(ngx_event_t *ev) b->last = b->start; } } + + if (n == NGX_AGAIN || n < (ssize_t) size) { + dst->write->available = 0; + if (ngx_handle_write_event(dst->write, NGX_LOWAT_EVENT) + == NGX_ERROR) + { + ngx_imap_proxy_close_session(s); + return; + } + } } } - if (src->read->ready && b->last < b->end) { - n = ngx_recv(src, b->last, b->end - b->last); + size = b->end - b->last; + + if (src->read->ready && size) { + n = ngx_recv(src, b->last, size); if (n == NGX_ERROR || n == 0) { ngx_imap_proxy_close_session(s); @@ -69,6 +274,13 @@ void ngx_imap_proxy_handler(ngx_event_t *ev) do_write = 1; b->last += n; } + + if (n == NGX_AGAIN || n < (ssize_t) size) { + if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + } } } while (data); @@ -77,4 +289,10 @@ void ngx_imap_proxy_handler(ngx_event_t *ev) static void ngx_imap_proxy_close_session(ngx_imap_session_t *s) { + if (ngx_close_socket(s->proxy->upstream.connection->fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + ngx_imap_close_connection(s->connection); } diff --git a/src/os/unix/ngx_send.c b/src/os/unix/ngx_send.c index 5a1a0ff29..2bcbdf9d7 100644 --- a/src/os/unix/ngx_send.c +++ b/src/os/unix/ngx_send.c @@ -42,6 +42,8 @@ ssize_t ngx_unix_send(ngx_connection_t *c, u_char *buf, size_t size) if (n == 0) { ngx_log_error(NGX_LOG_ALERT, c->log, err, "send() returned zero"); + wev->ready = 0; + return n; } if (err == NGX_EAGAIN || err == NGX_EINTR) { diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h index 5b126fb24..6bbe66bcf 100644 --- a/src/os/win32/ngx_win32_config.h +++ b/src/os/win32/ngx_win32_config.h @@ -97,6 +97,7 @@ typedef int ssize_t; typedef long time_t; typedef __int64 off_t; typedef uint32_t in_addr_t; +typedef u_short in_port_t; typedef int sig_atomic_t; typedef uint32_t ngx_atomic_t; |