diff src/imap/ngx_imap_proxy.c @ 419:47709bff4468

nginx-0.0.10-2004-09-09-19:40:48 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 09 Sep 2004 15:40:48 +0000
parents cf072d26d6d6
children edaefb2a20fc
line wrap: on
line diff
--- 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 
 
     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 
                         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 
                 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 
 
 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);
 }