diff src/event/ngx_event_openssl.c @ 22:8b6db3bda591 NGINX_0_1_11

nginx 0.1.11 *) Feature: the worker_priority directive. *) Change: both tcp_nopush and tcp_nodelay directives affect the transferred response. *) Bugfix: nginx did not call initgroups(). Thanks to Andrew Sitnikov and Andrei Nigmatulin. *) Change: now the ngx_http_autoindex_module shows the file size in the bytes. *) Bugfix: the ngx_http_autoindex_module returned the 500 error if the broken symlink was in a directory. *) Bugfix: the files bigger than 4G could not be transferred using sendfile. *) Bugfix: if the backend was resolved to several backends and there was an error while the response waiting then process may got caught in an endless loop. *) Bugfix: the worker process may exit with the "unknown cycle" message when the /dev/poll method was used. *) Bugfix: "close() channel failed" errors. *) Bugfix: the autodetection of the "nobody" and "nogroup" groups. *) Bugfix: the send_lowat directive did not work on Linux. *) Bugfix: the segmentation fault occurred if there was no events section in configuration. *) Bugfix: nginx could not be built on OpenBSD. *) Bugfix: the double slashes in "://" in the URI were converted to ":/".
author Igor Sysoev <http://sysoev.ru>
date Thu, 02 Dec 2004 00:00:00 +0300
parents 6f8b0dc0f8dd
children 7ca9bdc82b3f
line wrap: on
line diff
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -9,7 +9,9 @@
 #include <ngx_event.h>
 
 
+static void ngx_ssl_write_handler(ngx_event_t *wev);
 static ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
+static void ngx_ssl_read_handler(ngx_event_t *rev);
 
 
 ngx_int_t ngx_ssl_init(ngx_log_t *log)
@@ -69,6 +71,25 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); 
 
     if (n > 0) {
+        if (c->ssl->saved_write_handler) {
+
+            c->write->event_handler = c->ssl->saved_write_handler;
+            c->ssl->saved_write_handler = NULL;
+            c->write->ready = 1;
+
+            if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            ngx_post_event(c->write);
+
+            ngx_mutex_unlock(ngx_posted_events_mutex);
+        }
+
         return n;
     }
 
@@ -93,13 +114,27 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
     if (sslerr == SSL_ERROR_WANT_WRITE) {
         ngx_log_error(NGX_LOG_ALERT, c->log, err,
                       "SSL wants to write%s", handshake);
-        return NGX_ERROR;
-#if 0
+
+        c->write->ready = 0;
+
+        if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        /*
+         * we do not set the timer because there is already the read event timer
+         */
+
+        if (c->ssl->saved_write_handler == NULL) {
+            c->ssl->saved_write_handler = c->write->event_handler;
+            c->write->event_handler = ngx_ssl_write_handler;
+        }
+
         return NGX_AGAIN;
-#endif
     }
 
     c->ssl->no_rcv_shut = 1;
+    c->ssl->no_send_shut = 1;
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
         ngx_log_error(NGX_LOG_INFO, c->log, err,
@@ -115,9 +150,18 @@ ssize_t ngx_ssl_recv(ngx_connection_t *c
 }
 
 
+static void ngx_ssl_write_handler(ngx_event_t *wev)
+{
+    ngx_connection_t  *c;
+
+    c = wev->data;
+    c->read->event_handler(c->read);
+}
+
+
 /*
  * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
- * before SSL_write() call to decrease a SSL overhead.
+ * before the SSL_write() call to decrease a SSL overhead.
  *
  * Besides for protocols such as HTTP it is possible to always buffer
  * the output to decrease a SSL overhead some more.
@@ -155,6 +199,14 @@ ngx_chain_t *ngx_ssl_send_chain(ngx_conn
         return in;
     }
 
+
+    /* the maximum limit size is the maximum uint32_t value - the page size */
+
+    if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) {
+        limit = NGX_MAX_UINT32_VALUE - ngx_pagesize;
+    }
+
+
     send = 0;
     flush = (in == NULL) ? 1 : 0;
 
@@ -252,6 +304,25 @@ static ssize_t ngx_ssl_write(ngx_connect
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
 
     if (n > 0) {
+        if (c->ssl->saved_read_handler) {
+
+            c->read->event_handler = c->ssl->saved_read_handler;
+            c->ssl->saved_read_handler = NULL;
+            c->read->ready = 1;
+
+            if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+
+            ngx_post_event(c->read);
+
+            ngx_mutex_unlock(ngx_posted_events_mutex);
+        }
+
         return n;
     }
 
@@ -277,13 +348,28 @@ static ssize_t ngx_ssl_write(ngx_connect
 
         ngx_log_error(NGX_LOG_ALERT, c->log, err,
                       "SSL wants to read%s", handshake);
-        return NGX_ERROR;
-#if 0
+
+        c->read->ready = 0;
+
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        /*
+         * we do not set the timer because there is already
+         * the write event timer
+         */
+
+        if (c->ssl->saved_read_handler == NULL) {
+            c->ssl->saved_read_handler = c->read->event_handler;
+            c->read->event_handler = ngx_ssl_read_handler;
+        }
+
         return NGX_AGAIN;
-#endif
     }
 
     c->ssl->no_rcv_shut = 1;
+    c->ssl->no_send_shut = 1;
 
     ngx_ssl_error(NGX_LOG_ALERT, c->log, err, "SSL_write() failed");
 
@@ -291,21 +377,42 @@ static ssize_t ngx_ssl_write(ngx_connect
 }
 
 
+static void ngx_ssl_read_handler(ngx_event_t *rev)
+{
+    ngx_connection_t  *c;
+
+    c = rev->data;
+    c->write->event_handler(c->write);
+}
+
+
 ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c)
 {
-    int         n, sslerr;
+    int         n, sslerr, mode;
     ngx_uint_t  again;
 
-    if (c->timedout) {
-        SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN);
+    if (!c->ssl->shutdown_set) {
+
+        /* it seems that SSL_set_shutdown() could be called once only */
+
+        if (c->read->timedout) {
+            mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
 
-    } else {
-        if (c->ssl->no_rcv_shut) {
-            SSL_set_shutdown(c->ssl->ssl, SSL_RECEIVED_SHUTDOWN);
+        } else {
+            mode = 0;
+
+            if (c->ssl->no_rcv_shut) {
+                mode = SSL_RECEIVED_SHUTDOWN;
+            }
+
+            if (c->ssl->no_send_shut) {
+                mode |= SSL_SENT_SHUTDOWN;
+            }
         }
 
-        if (c->ssl->no_send_shut) {
-            SSL_set_shutdown(c->ssl->ssl, SSL_SENT_SHUTDOWN);
+        if (mode) {
+            SSL_set_shutdown(c->ssl->ssl, mode);
+            c->ssl->shutdown_set = 1;
         }
     }
 
@@ -319,17 +426,17 @@ ngx_int_t ngx_ssl_shutdown(ngx_connectio
 
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
 
+        if (n == 1 || (n == 0 && c->read->timedout)) {
+            SSL_free(c->ssl->ssl);
+            c->ssl = NULL;
+            return NGX_OK;
+        }
+
         if (n == 0) {
             again = 1;
             break;
         }
 
-        if (n == 1) {
-            SSL_free(c->ssl->ssl);
-            c->ssl = NULL;
-            return NGX_OK;
-        }
-
         break;
     }
 
@@ -342,7 +449,7 @@ ngx_int_t ngx_ssl_shutdown(ngx_connectio
 
     if (again || sslerr == SSL_ERROR_WANT_READ) {
 
-        ngx_add_timer(c->read, 10000);
+        ngx_add_timer(c->read, 30000);
 
         if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
             return NGX_ERROR;