nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev
17 years ago
298 | 298 | IMAP_MODULE=ngx_imap_module |
299 | 299 | IMAP_SRCS="src/imap/ngx_imap.c \ |
300 | 300 | src/imap/ngx_imap_handler.c \ |
301 | src/imap/ngx_imap_parse.c \ | |
301 | 302 | src/imap/ngx_imap_proxy.c" |
48 | 48 | #if (HAVE_DEFERRED_ACCEPT) |
49 | 49 | unsigned deferred_accept:1; |
50 | 50 | #endif |
51 | ||
52 | unsigned addr_ntop:1; | |
51 | 53 | } ngx_listening_t; |
52 | 54 | |
53 | 55 |
10 | 10 | } ngx_accept_log_ctx_t; |
11 | 11 | |
12 | 12 | |
13 | static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log); | |
13 | 14 | static size_t ngx_accept_log_error(void *data, char *buf, size_t len); |
14 | 15 | |
15 | 16 | |
137 | 138 | "closing the connection", |
138 | 139 | ls->listening->addr_text.data, s, ecf->connections); |
139 | 140 | |
140 | if (ngx_close_socket(s) == -1) { | |
141 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
142 | ngx_close_socket_n "failed"); | |
143 | } | |
144 | ||
141 | ngx_close_accepted_socket(s, log); | |
145 | 142 | ngx_destroy_pool(pool); |
146 | 143 | return; |
147 | 144 | } |
154 | 151 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, |
155 | 152 | ngx_blocking_n " failed"); |
156 | 153 | |
157 | if (ngx_close_socket(s) == -1) { | |
158 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
159 | ngx_close_socket_n " failed"); | |
160 | } | |
161 | ||
154 | ngx_close_accepted_socket(s, log); | |
162 | 155 | ngx_destroy_pool(pool); |
163 | 156 | return; |
164 | 157 | } |
170 | 163 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, |
171 | 164 | ngx_nonblocking_n " failed"); |
172 | 165 | |
173 | if (ngx_close_socket(s) == -1) { | |
174 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
175 | ngx_close_socket_n " failed"); | |
176 | } | |
177 | ||
166 | ngx_close_accepted_socket(s, log); | |
178 | 167 | ngx_destroy_pool(pool); |
179 | 168 | return; |
180 | 169 | } |
285 | 274 | ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, |
286 | 275 | "accept: fd:%d c:%d", s, c->number); |
287 | 276 | |
277 | if (c->listening->addr_ntop) { | |
278 | c->addr_text.data = ngx_palloc(c->pool, | |
279 | c->listening->addr_text_max_len); | |
280 | if (c->addr_text.data == NULL) { | |
281 | ngx_close_accepted_socket(s, log); | |
282 | ngx_destroy_pool(pool); | |
283 | return; | |
284 | } | |
285 | ||
286 | c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, | |
287 | c->addr_text.data, | |
288 | c->listening->addr_text_max_len); | |
289 | if (c->addr_text.len == 0) { | |
290 | ngx_close_accepted_socket(s, log); | |
291 | ngx_destroy_pool(pool); | |
292 | return; | |
293 | } | |
294 | } | |
295 | ||
288 | 296 | #if (NGX_DEBUG) |
289 | 297 | { |
290 | 298 | |
306 | 314 | |
307 | 315 | if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) { |
308 | 316 | if (ngx_add_conn(c) == NGX_ERROR) { |
309 | if (ngx_close_socket(s) == -1) { | |
310 | ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_socket_errno, | |
311 | ngx_close_socket_n " failed"); | |
312 | } | |
313 | ||
317 | ngx_close_accepted_socket(s, log); | |
314 | 318 | ngx_destroy_pool(pool); |
315 | 319 | return; |
316 | 320 | } |
439 | 443 | } |
440 | 444 | |
441 | 445 | |
446 | static void ngx_close_accepted_socket(ngx_socket_t s, ngx_log_t *log) | |
447 | { | |
448 | if (ngx_close_socket(s) == -1) { | |
449 | ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno, | |
450 | ngx_close_socket_n " failed"); | |
451 | } | |
452 | } | |
453 | ||
454 | ||
442 | 455 | static size_t ngx_accept_log_error(void *data, char *buf, size_t len) |
443 | 456 | { |
444 | 457 | ngx_accept_log_ctx_t *ctx = data; |
12 | 12 | typedef struct { |
13 | 13 | in_addr_t addr; |
14 | 14 | ngx_str_t host; |
15 | int port; | |
15 | in_port_t port; | |
16 | 16 | ngx_str_t addr_port_text; |
17 | 17 | |
18 | int fails; | |
18 | ngx_int_t fails; | |
19 | 19 | time_t accessed; |
20 | 20 | } ngx_peer_t; |
21 | 21 | |
22 | 22 | |
23 | 23 | typedef struct { |
24 | int current; | |
25 | int number; | |
26 | int max_fails; | |
27 | int fail_timeout; | |
28 | int last_cached; | |
24 | ngx_int_t current; | |
25 | ngx_int_t number; | |
26 | ngx_int_t max_fails; | |
27 | ngx_int_t fail_timeout; | |
28 | ngx_int_t last_cached; | |
29 | 29 | |
30 | 30 | /* ngx_mutex_t *mutex; */ |
31 | 31 | ngx_connection_t **cached; |
36 | 36 | |
37 | 37 | typedef struct { |
38 | 38 | ngx_peers_t *peers; |
39 | int cur_peer; | |
40 | int tries; | |
39 | ngx_int_t cur_peer; | |
40 | ngx_int_t tries; | |
41 | 41 | |
42 | 42 | ngx_connection_t *connection; |
43 | 43 | #if (NGX_THREADS) |
1226 | 1226 | u->port_text.len = &url->data[i] - u->port_text.data; |
1227 | 1227 | |
1228 | 1228 | if (u->port_text.len > 0) { |
1229 | u->port = ngx_atoi(u->port_text.data, u->port_text.len); | |
1229 | u->port = (in_port_t) ngx_atoi(u->port_text.data, | |
1230 | u->port_text.len); | |
1230 | 1231 | if (u->port > 0) { |
1231 | 1232 | |
1232 | 1233 | if (u->port == 80) { |
1262 | 1263 | u->port_text.len = &url->data[i] - u->port_text.data; |
1263 | 1264 | |
1264 | 1265 | if (u->port_text.len > 0) { |
1265 | u->port = ngx_atoi(u->port_text.data, u->port_text.len); | |
1266 | u->port = (in_port_t) ngx_atoi(u->port_text.data, u->port_text.len); | |
1266 | 1267 | if (u->port > 0) { |
1267 | 1268 | u->port = htons(u->port); |
1268 | 1269 | return NULL; |
53 | 53 | |
54 | 54 | static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
55 | 55 | { |
56 | char *rv; | |
56 | 57 | ngx_uint_t mi, m, s, l, p, a, n; |
57 | 58 | ngx_uint_t port_found, addr_found, virtual_names; |
58 | char *rv; | |
59 | struct sockaddr_in *addr_in; | |
60 | 59 | ngx_conf_t pcf; |
61 | 60 | ngx_array_t in_ports; |
62 | 61 | ngx_listening_t *ls; |
513 | 512 | ls->nonblocking = 0; |
514 | 513 | #endif |
515 | 514 | #endif |
515 | ls->addr_ntop = 1; | |
516 | 516 | |
517 | 517 | ls->handler = ngx_http_init_connection; |
518 | 518 |
64 | 64 | |
65 | 65 | if (r->method_end - m == 3) { |
66 | 66 | |
67 | if (*m == 'G' && *(m + 1) == 'E' && *(m + 2) == 'T') { | |
67 | if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { | |
68 | 68 | r->method = NGX_HTTP_GET; |
69 | 69 | } |
70 | 70 | |
71 | 71 | } else if (r->method_end - m == 4) { |
72 | 72 | |
73 | if (*m == 'P' && *(m + 1) == 'O' | |
74 | && *(m + 2) == 'T' && *(m + 3) == 'T') | |
73 | if (m[0] == 'P' && m[1] == 'O' | |
74 | && m[2] == 'T' && m[3] == 'T') | |
75 | 75 | { |
76 | 76 | r->method = NGX_HTTP_POST; |
77 | 77 | |
78 | } else if (*m == 'H' && *(m + 1) == 'E' | |
79 | && *(m + 2) == 'A' && *(m + 3) == 'D') | |
78 | } else if (m[0] == 'H' && m[1] == 'E' | |
79 | && m[2] == 'A' && m[3] == 'D') | |
80 | 80 | { |
81 | 81 | r->method = NGX_HTTP_HEAD; |
82 | 82 | } |
95 | 95 | { |
96 | 96 | ngx_event_t *rev; |
97 | 97 | ngx_http_log_ctx_t *ctx; |
98 | ||
99 | c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len); | |
100 | if (c->addr_text.data == NULL) { | |
101 | ngx_http_close_connection(c); | |
102 | return; | |
103 | } | |
104 | ||
105 | c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr, | |
106 | c->addr_text.data, | |
107 | c->listening->addr_text_max_len); | |
108 | ||
109 | if (c->addr_text.len == 0) { | |
110 | ngx_http_close_connection(c); | |
111 | return; | |
112 | } | |
113 | 98 | |
114 | 99 | if (!(ctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) { |
115 | 100 | ngx_http_close_connection(c); |
310 | 310 | ngx_uint_t headers_n; |
311 | 311 | |
312 | 312 | /* used to parse HTTP headers */ |
313 | ngx_int_t state; | |
313 | ngx_uint_t state; | |
314 | 314 | u_char *uri_start; |
315 | 315 | u_char *uri_end; |
316 | 316 | u_char *uri_ext; |
49 | 49 | } |
50 | 50 | |
51 | 51 | ls->backlog = -1; |
52 | ls->addr_ntop = 1; | |
52 | 53 | ls->handler = ngx_imap_init_connection; |
53 | 54 | ls->pool_size = 16384; |
54 | 55 | /* ls->post_accept_timeout = 0; */ |
3 | 3 | |
4 | 4 | #include <ngx_config.h> |
5 | 5 | #include <ngx_core.h> |
6 | #include <ngx_event.h> | |
7 | #include <ngx_event_connect.h> | |
6 | 8 | |
7 | 9 | |
8 | 10 | typedef struct { |
9 | ngx_connection_t *connection; | |
11 | ngx_peer_connection_t upstream; | |
10 | 12 | |
11 | ngx_buf_t *downstream_buffer; | |
12 | ngx_buf_t *upstream_buffer; | |
13 | ngx_buf_t *buffer; | |
13 | 14 | } ngx_imap_proxy_ctx_t; |
14 | 15 | |
15 | 16 | |
16 | 17 | typedef struct { |
17 | uint32_t signature; /* "IMAP" */ | |
18 | uint32_t signature; /* "IMAP" */ | |
18 | 19 | |
19 | ngx_connection_t *connection; | |
20 | ngx_imap_proxy_ctx_t *proxy; | |
20 | ngx_connection_t *connection; | |
21 | ngx_buf_t *buffer; | |
22 | ||
23 | ngx_imap_proxy_ctx_t *proxy; | |
24 | ||
25 | ngx_uint_t command; | |
26 | ngx_array_t args; | |
27 | ||
28 | /* used to parse IMAP/POP3 command */ | |
29 | ||
30 | ngx_uint_t state; | |
31 | u_char *arg_start; | |
32 | u_char *arg_end; | |
21 | 33 | } ngx_imap_session_t; |
22 | 34 | |
23 | 35 | |
24 | #define NGX_POP3_USER 1 | |
25 | #define NGX_POP3_PASS 2 | |
26 | #define NGX_POP3_APOP 3 | |
27 | #define NGX_POP3_STAT 4 | |
28 | #define NGX_POP3_LIST 5 | |
29 | #define NGX_POP3_RETR 6 | |
30 | #define NGX_POP3_DELE 7 | |
31 | #define NGX_POP3_NOOP 8 | |
32 | #define NGX_POP3_RSET 9 | |
33 | #define NGX_POP3_TOP 10 | |
34 | #define NGX_POP3_UIDL 11 | |
35 | #define NGX_POP3_QUIT 12 | |
36 | #define NGX_POP3_USER 1 | |
37 | #define NGX_POP3_PASS 2 | |
38 | #define NGX_POP3_APOP 3 | |
39 | #define NGX_POP3_STAT 4 | |
40 | #define NGX_POP3_LIST 5 | |
41 | #define NGX_POP3_RETR 6 | |
42 | #define NGX_POP3_DELE 7 | |
43 | #define NGX_POP3_NOOP 8 | |
44 | #define NGX_POP3_RSET 9 | |
45 | #define NGX_POP3_TOP 10 | |
46 | #define NGX_POP3_UIDL 11 | |
47 | #define NGX_POP3_QUIT 12 | |
48 | ||
49 | ||
50 | #define NGX_IMAP_PARSE_INVALID_COMMAND 10 | |
51 | ||
52 | ||
53 | #define NGX_IMAP_PROXY_INVALID 10 | |
54 | #define NGX_IMAP_PROXY_ERROR 11 | |
36 | 55 | |
37 | 56 | |
38 | 57 | void ngx_imap_init_connection(ngx_connection_t *c); |
39 | 58 | void ngx_imap_close_connection(ngx_connection_t *c); |
40 | 59 | |
60 | void ngx_imap_proxy_init(ngx_imap_session_t *s); | |
61 | ||
62 | ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s); | |
63 | ||
41 | 64 | |
42 | 65 | #endif /* _NGX_IMAP_H_INCLUDED_ */ |
5 | 5 | #include <nginx.h> |
6 | 6 | |
7 | 7 | |
8 | static void ngx_imap_auth_state(ngx_event_t *rev); | |
8 | static void ngx_imap_init_session(ngx_event_t *rev); | |
9 | 9 | |
10 | 10 | |
11 | 11 | static char pop3_greeting[] = "+OK " NGINX_VER " ready" CRLF; |
14 | 14 | |
15 | 15 | void ngx_imap_init_connection(ngx_connection_t *c) |
16 | 16 | { |
17 | ngx_int_t n; | |
17 | char *greeting; | |
18 | ssize_t size; | |
19 | ngx_int_t n; | |
18 | 20 | |
19 | 21 | ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, |
20 | 22 | "imap init connection"); |
21 | 23 | |
22 | 24 | c->log_error = NGX_ERROR_INFO; |
23 | 25 | |
24 | n = ngx_send(c, pop3_greeting, sizeof(pop3_greeting) - 1); | |
26 | greeting = pop3_greeting; | |
27 | size = sizeof(pop3_greeting) - 1; | |
25 | 28 | |
26 | if (n == NGX_ERROR) { | |
29 | n = ngx_send(c, greeting, size); | |
30 | ||
31 | if (n < size) { | |
32 | /* | |
33 | * we treat the incomplete sending as NGX_ERROR | |
34 | * because it is very strange here | |
35 | */ | |
27 | 36 | ngx_imap_close_connection(c); |
28 | 37 | return; |
29 | 38 | } |
30 | 39 | |
31 | c->read->event_handler = ngx_imap_auth_state; | |
40 | c->read->event_handler = ngx_imap_init_session; | |
41 | ||
42 | ngx_add_timer(c->read, /* STUB */ 60000); | |
32 | 43 | |
33 | 44 | if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { |
34 | 45 | ngx_imap_close_connection(c); |
35 | return; | |
36 | 46 | } |
37 | 47 | } |
38 | 48 | |
39 | 49 | |
40 | static void ngx_imap_auth_state(ngx_event_t *rev) | |
50 | static void ngx_imap_init_session(ngx_event_t *rev) | |
41 | 51 | { |
42 | ngx_connection_t *c; | |
52 | ngx_connection_t *c; | |
53 | ngx_imap_session_t *s; | |
43 | 54 | |
44 | 55 | c = rev->data; |
45 | 56 | |
46 | ngx_imap_close_connection(c); | |
57 | if (!(s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)))) { | |
58 | ngx_imap_close_connection(c); | |
59 | return; | |
60 | } | |
61 | ||
62 | c->data = s; | |
63 | s->connection = c; | |
64 | ||
65 | if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { | |
66 | ngx_imap_close_connection(s->connection); | |
67 | return; | |
68 | } | |
69 | ||
70 | s->buffer = ngx_create_temp_buf(s->connection->pool, /* STUB */ 4096); | |
71 | if (s->buffer == NULL) { | |
72 | ngx_imap_close_connection(s->connection); | |
73 | return; | |
74 | } | |
75 | ||
76 | ngx_imap_proxy_init(s); | |
47 | 77 | } |
48 | 78 | |
49 | 79 |
4 | 4 | #include <ngx_imap.h> |
5 | 5 | |
6 | 6 | |
7 | ngx_int_t ngx_pop3_parse_command(ngx_imap_request_t *r) | |
7 | ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s) | |
8 | 8 | { |
9 | u_char ch, *p, *c; | |
9 | u_char ch, *p, *c; | |
10 | ngx_str_t *arg; | |
10 | 11 | enum { |
11 | 12 | sw_start = 0, |
13 | sw_spaces_before_argument, | |
14 | sw_argument, | |
15 | sw_almost_done, | |
12 | 16 | sw_done |
13 | 17 | } state; |
14 | 18 | |
15 | while (p < r->buf->last && state < sw_done) { | |
19 | state = s->state; | |
20 | p = s->buffer->pos; | |
21 | ||
22 | while (p < s->buffer->last && state < sw_done) { | |
16 | 23 | ch = *p++; |
17 | 24 | |
18 | 25 | switch (state) { |
19 | 26 | |
20 | /* POP3 commands */ | |
27 | /* POP3 command */ | |
28 | ||
21 | 29 | case sw_start: |
22 | if (ch == ' ') { | |
23 | c = r->buf->start; | |
30 | if (ch == ' ' || ch == CR || ch == LF) { | |
31 | c = s->buffer->start; | |
24 | 32 | |
25 | if (p - 1 - m == 4) { | |
33 | if (p - 1 - c == 4) { | |
26 | 34 | |
27 | if (*c == 'U' && *(c + 1) == 'S' | |
28 | && *(c + 2) == 'E' && *(c + 3) == 'R') | |
35 | if (c[0] == 'U' && c[1] == 'S' | |
36 | && c[2] == 'E' && c[3] == 'R') | |
29 | 37 | { |
30 | r->command = NGX_POP3_USER; | |
38 | s->command = NGX_POP3_USER; | |
31 | 39 | |
32 | } else if (*c == 'P' && *(c + 1) == 'A' | |
33 | && *(c + 2) == 'A' && *(c + 3) == 'S') | |
40 | } else if (c[0] == 'P' && c[1] == 'A' | |
41 | && c[2] == 'A' && c[3] == 'S') | |
34 | 42 | { |
35 | r->method = NGX_POP3_PASS; | |
43 | s->command = NGX_POP3_PASS; | |
36 | 44 | |
37 | } else if (*c == 'Q' && *(c + 1) == 'U' | |
38 | && *(c + 2) == 'I' && *(c + 3) == 'T') | |
45 | } else if (c[0] == 'Q' && c[1] == 'U' | |
46 | && c[2] == 'I' && c[3] == 'T') | |
39 | 47 | { |
40 | r->method = NGX_POP3_QUIT; | |
48 | s->command = NGX_POP3_QUIT; | |
41 | 49 | |
42 | } else if (*c == 'N' && *(c + 1) == 'O' | |
43 | && *(c + 2) == 'O' && *(c + 3) == 'P') | |
50 | #if 0 | |
51 | } else if (c[0] == 'N' && c[1] == 'O' | |
52 | && c[2] == 'O' && c[3] == 'P') | |
44 | 53 | { |
45 | r->method = NGX_POP3_NOOP; | |
54 | s->command = NGX_POP3_NOOP; | |
55 | #endif | |
56 | ||
57 | } else { | |
58 | return NGX_IMAP_PARSE_INVALID_COMMAND; | |
46 | 59 | } |
60 | ||
61 | } else { | |
62 | return NGX_IMAP_PARSE_INVALID_COMMAND; | |
47 | 63 | } |
48 | 64 | |
49 | state = sw_spaces_before_arg; | |
65 | switch (ch) { | |
66 | case ' ': | |
67 | state = sw_spaces_before_argument; | |
68 | break; | |
69 | case CR: | |
70 | state = sw_almost_done; | |
71 | break; | |
72 | case LF: | |
73 | state = sw_done; | |
74 | break; | |
75 | } | |
50 | 76 | break; |
51 | 77 | } |
52 | 78 | |
55 | 81 | } |
56 | 82 | |
57 | 83 | break; |
58 | } | |
84 | ||
85 | /* the spaces before the argument */ | |
86 | case sw_spaces_before_argument: | |
87 | switch (ch) { | |
88 | case ' ': | |
89 | break; | |
90 | case CR: | |
91 | state = sw_almost_done; | |
92 | s->arg_end = p - 1; | |
93 | break; | |
94 | case LF: | |
95 | state = sw_done; | |
96 | s->arg_end = p - 1; | |
97 | break; | |
98 | default: | |
99 | if (s->args.nelts > 2) { | |
100 | return NGX_IMAP_PARSE_INVALID_COMMAND; | |
101 | } | |
102 | ||
103 | state = sw_argument; | |
104 | s->arg_start = p - 1; | |
105 | break; | |
106 | } | |
107 | break; | |
108 | ||
109 | /* the argument */ | |
110 | case sw_argument: | |
111 | switch (ch) { | |
112 | case ' ': | |
113 | case CR: | |
114 | case LF: | |
115 | if (!(arg = ngx_array_push(&s->args))) { | |
116 | return NGX_ERROR; | |
117 | } | |
118 | arg->len = p - s->arg_start; | |
119 | arg->data = s->arg_start; | |
120 | s->arg_start = NULL; | |
121 | ||
122 | switch (ch) { | |
123 | case ' ': | |
124 | state = sw_spaces_before_argument; | |
125 | break; | |
126 | case CR: | |
127 | state = sw_almost_done; | |
128 | break; | |
129 | case LF: | |
130 | state = sw_done; | |
131 | break; | |
132 | } | |
133 | break; | |
134 | ||
135 | default: | |
136 | break; | |
137 | } | |
138 | break; | |
139 | ||
140 | /* end of request line */ | |
141 | case sw_almost_done: | |
142 | switch (ch) { | |
143 | case LF: | |
144 | state = sw_done; | |
145 | break; | |
146 | default: | |
147 | return NGX_IMAP_PARSE_INVALID_COMMAND; | |
148 | } | |
149 | break; | |
59 | 150 | |
60 | 151 | /* suppress warning */ |
61 | 152 | case sw_done: |
63 | 154 | } |
64 | 155 | } |
65 | 156 | |
66 | return NGX_OK; | |
157 | s->buffer->pos = p; | |
158 | ||
159 | if (state == sw_done) { | |
160 | if (s->arg_start) { | |
161 | if (!(arg = ngx_array_push(&s->args))) { | |
162 | return NGX_ERROR; | |
163 | } | |
164 | arg->len = s->arg_end - s->arg_start; | |
165 | arg->data = s->arg_start; | |
166 | s->arg_start = NULL; | |
167 | } | |
168 | ||
169 | return NGX_OK; | |
170 | ||
171 | } else { | |
172 | s->state = state; | |
173 | return NGX_AGAIN; | |
174 | } | |
67 | 175 | } |
1 | 1 | #include <ngx_config.h> |
2 | 2 | #include <ngx_core.h> |
3 | 3 | #include <ngx_event.h> |
4 | #include <ngx_event_connect.h> | |
4 | 5 | #include <ngx_imap.h> |
5 | 6 | |
6 | 7 | |
8 | static void ngx_imap_proxy_block_read(ngx_event_t *rev); | |
9 | static void ngx_imap_proxy_greeting_handler(ngx_event_t *rev); | |
10 | static void ngx_imap_proxy_init_handler(ngx_event_t *wev); | |
11 | static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev); | |
12 | static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s); | |
13 | static void ngx_imap_proxy_handler(ngx_event_t *ev); | |
7 | 14 | static void ngx_imap_proxy_close_session(ngx_imap_session_t *s); |
8 | 15 | |
9 | 16 | |
10 | void ngx_imap_proxy_handler(ngx_event_t *ev) | |
11 | { | |
17 | void ngx_imap_proxy_init(ngx_imap_session_t *s) | |
18 | { | |
19 | ngx_int_t rc; | |
20 | ngx_peers_t *peers; | |
21 | ngx_imap_proxy_ctx_t *p; | |
22 | ||
23 | if (!(p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t)))) { | |
24 | ngx_imap_close_connection(s->connection); | |
25 | return; | |
26 | } | |
27 | ||
28 | s->proxy = p; | |
29 | ||
30 | /**/ | |
31 | ||
32 | if (!(peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t)))) { | |
33 | ngx_imap_close_connection(s->connection); | |
34 | return; | |
35 | } | |
36 | ||
37 | p->upstream.peers = peers; | |
38 | p->upstream.log = s->connection->log; | |
39 | p->upstream.log_error = NGX_ERROR_ERR; | |
40 | ||
41 | peers->number = 1; | |
42 | peers->max_fails = 1; | |
43 | peers->peers[0].addr = inet_addr("81.19.69.70"); | |
44 | peers->peers[0].addr_port_text.len = sizeof("81.19.69.70:110") - 1; | |
45 | peers->peers[0].addr_port_text.data = "81.19.69.70:110"; | |
46 | peers->peers[0].port = htons(110); | |
47 | ||
48 | rc = ngx_event_connect_peer(&p->upstream); | |
49 | ||
50 | if (rc == NGX_ERROR) { | |
51 | ngx_imap_proxy_close_session(s); | |
52 | return; | |
53 | } | |
54 | ||
55 | p->upstream.connection->data = s; | |
56 | p->upstream.connection->pool = s->connection->pool; | |
57 | ||
58 | s->connection->read->event_handler = ngx_imap_proxy_block_read; | |
59 | p->upstream.connection->read->event_handler = | |
60 | ngx_imap_proxy_greeting_handler; | |
61 | p->upstream.connection->write->event_handler = ngx_imap_proxy_dummy_handler; | |
62 | } | |
63 | ||
64 | ||
65 | static void ngx_imap_proxy_block_read(ngx_event_t *rev) | |
66 | { | |
67 | ngx_connection_t *c; | |
68 | ngx_imap_session_t *s; | |
69 | ||
70 | ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy block read"); | |
71 | ||
72 | if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { | |
73 | c = rev->data; | |
74 | s = c->data; | |
75 | ||
76 | ngx_imap_proxy_close_session(s); | |
77 | } | |
78 | } | |
79 | ||
80 | ||
81 | static void ngx_imap_proxy_greeting_handler(ngx_event_t *rev) | |
82 | { | |
83 | ngx_int_t rc; | |
84 | ngx_buf_t *b; | |
85 | ngx_connection_t *c; | |
86 | ngx_imap_session_t *s; | |
87 | ||
88 | ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, | |
89 | "imap proxy greeting handler"); | |
90 | ||
91 | c = rev->data; | |
92 | s = c->data; | |
93 | ||
94 | if (s->proxy->buffer == NULL) { | |
95 | s->proxy->buffer = ngx_create_temp_buf(c->pool, /* STUB */ 4096); | |
96 | if (s->proxy->buffer == NULL) { | |
97 | ngx_imap_proxy_close_session(s); | |
98 | return; | |
99 | } | |
100 | } | |
101 | ||
102 | rc = ngx_imap_proxy_read_response(s); | |
103 | ||
104 | if (rc == NGX_AGAIN) { | |
105 | return; | |
106 | } | |
107 | ||
108 | if (rc == NGX_OK) { | |
109 | s->connection->read->event_handler = ngx_imap_proxy_handler; | |
110 | s->connection->write->event_handler = ngx_imap_proxy_handler; | |
111 | rev->event_handler = ngx_imap_proxy_handler; | |
112 | c->write->event_handler = ngx_imap_proxy_handler; | |
113 | ||
114 | b = s->proxy->buffer; | |
115 | b->pos = b->start; | |
116 | b->last = b->start; | |
117 | ||
118 | if (ngx_handle_read_event(s->connection->read, 0) == NGX_ERROR) { | |
119 | ngx_imap_proxy_close_session(s); | |
120 | return; | |
121 | } | |
122 | ||
123 | if (s->connection->read->ready) { | |
124 | ngx_imap_proxy_handler(s->connection->read); | |
125 | } | |
126 | ||
127 | return; | |
128 | } | |
129 | ||
130 | /* TODO: ngx_imap_proxy_finalize_session(s, NGX_IMAP_INTERNAL_ERROR) */ | |
131 | ngx_imap_proxy_close_session(s); | |
132 | } | |
133 | ||
134 | ||
135 | static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev) | |
136 | { | |
137 | ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); | |
138 | } | |
139 | ||
140 | ||
141 | static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s) | |
142 | { | |
143 | u_char *p; | |
144 | ssize_t n; | |
145 | ngx_buf_t *b; | |
146 | ||
147 | b = s->proxy->buffer; | |
148 | ||
149 | n = ngx_recv(s->proxy->upstream.connection, b->last, b->end - b->last); | |
150 | ||
151 | if (n == NGX_ERROR || n == 0) { | |
152 | return NGX_ERROR; | |
153 | } | |
154 | ||
155 | if (n == NGX_AGAIN) { | |
156 | return NGX_AGAIN; | |
157 | } | |
158 | ||
159 | b->last += n; | |
160 | ||
161 | if (b->last - b->pos < 5) { | |
162 | return NGX_AGAIN; | |
163 | } | |
164 | ||
165 | if (*(b->last - 2) != CR || *(b->last - 1) != LF) { | |
166 | if (b->last == b->end) { | |
167 | *(b->last - 1) = '\0'; | |
168 | ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
169 | "upstream sent too long response line: \"%s\"", | |
170 | b->pos); | |
171 | return NGX_IMAP_PROXY_INVALID; | |
172 | } | |
173 | ||
174 | return NGX_AGAIN; | |
175 | } | |
176 | ||
177 | p = b->pos; | |
178 | ||
179 | if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') { | |
180 | return NGX_OK; | |
181 | } | |
182 | ||
183 | if (p[0] == '-' && p[1] == 'E' && p[2] == 'R' && p[3] == 'R') { | |
184 | return NGX_IMAP_PROXY_ERROR; | |
185 | } | |
186 | ||
187 | *(b->last - 2) = '\0'; | |
188 | ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
189 | "upstream sent invalid greeting line: \"%s\"", p); | |
190 | ||
191 | return NGX_IMAP_PROXY_INVALID; | |
192 | } | |
193 | ||
194 | ||
195 | static void ngx_imap_proxy_handler(ngx_event_t *ev) | |
196 | { | |
197 | size_t size; | |
12 | 198 | ssize_t n; |
13 | 199 | ngx_buf_t *b; |
14 | 200 | ngx_uint_t data, do_write; |
20 | 206 | |
21 | 207 | if (c == s->connection) { |
22 | 208 | src = c; |
23 | dst = s->proxy->connection; | |
24 | b = s->proxy->downstream_buffer; | |
209 | dst = s->proxy->upstream.connection; | |
210 | b = s->buffer; | |
25 | 211 | |
26 | 212 | } else { |
27 | src = s->proxy->connection; | |
28 | dst = c; | |
29 | b = s->proxy->upstream_buffer; | |
213 | src = c; | |
214 | dst = s->connection; | |
215 | b = s->proxy->buffer; | |
30 | 216 | } |
31 | 217 | |
32 | 218 | do_write = ev->write ? 1 : 0; |
219 | ||
220 | ngx_log_debug3(NGX_LOG_DEBUG_IMAP, ev->log, 0, | |
221 | "imap proxy handler: %d, #%d > #%d", | |
222 | do_write, src->fd, dst->fd); | |
33 | 223 | |
34 | 224 | do { |
35 | 225 | data = 0; |
36 | 226 | |
37 | 227 | if (do_write == 1) { |
38 | if (dst->write->ready && b->pos < b->last) { | |
39 | n = ngx_send(dst, b->pos, b->last - b->pos); | |
228 | ||
229 | size = b->last - b->pos; | |
230 | ||
231 | if (dst->write->ready && size) { | |
232 | n = ngx_send(dst, b->pos, size); | |
40 | 233 | |
41 | 234 | if (n == NGX_ERROR) { |
42 | 235 | ngx_imap_proxy_close_session(s); |
52 | 245 | b->last = b->start; |
53 | 246 | } |
54 | 247 | } |
55 | } | |
56 | } | |
57 | ||
58 | if (src->read->ready && b->last < b->end) { | |
59 | n = ngx_recv(src, b->last, b->end - b->last); | |
248 | ||
249 | if (n == NGX_AGAIN || n < (ssize_t) size) { | |
250 | dst->write->available = 0; | |
251 | if (ngx_handle_write_event(dst->write, NGX_LOWAT_EVENT) | |
252 | == NGX_ERROR) | |
253 | { | |
254 | ngx_imap_proxy_close_session(s); | |
255 | return; | |
256 | } | |
257 | } | |
258 | } | |
259 | } | |
260 | ||
261 | size = b->end - b->last; | |
262 | ||
263 | if (src->read->ready && size) { | |
264 | n = ngx_recv(src, b->last, size); | |
60 | 265 | |
61 | 266 | if (n == NGX_ERROR || n == 0) { |
62 | 267 | ngx_imap_proxy_close_session(s); |
68 | 273 | do_write = 1; |
69 | 274 | b->last += n; |
70 | 275 | } |
276 | ||
277 | if (n == NGX_AGAIN || n < (ssize_t) size) { | |
278 | if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) { | |
279 | ngx_imap_proxy_close_session(s); | |
280 | return; | |
281 | } | |
282 | } | |
71 | 283 | } |
72 | 284 | |
73 | 285 | } while (data); |
76 | 288 | |
77 | 289 | static void ngx_imap_proxy_close_session(ngx_imap_session_t *s) |
78 | 290 | { |
79 | } | |
291 | if (ngx_close_socket(s->proxy->upstream.connection->fd) == -1) { | |
292 | ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, | |
293 | ngx_close_socket_n " failed"); | |
294 | } | |
295 | ||
296 | ngx_imap_close_connection(s->connection); | |
297 | } |