using non-blocking IO for SSL_accept aio

Fri, 12 Jan 2018 17:54:52 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 12 Jan 2018 17:54:52 +0100
branch
aio
changeset 188
0e6a05c779e0
parent 187
4384bfbb7e26
child 189
a2438f6d1e73

using non-blocking IO for SSL_accept

src/server/daemon/httplistener.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/httplistener.c	Wed Jan 10 18:47:37 2018 +0100
+++ b/src/server/daemon/httplistener.c	Fri Jan 12 17:54:52 2018 +0100
@@ -402,33 +402,24 @@
         conn->fd = clientfd;
         conn->listener = ls;
         if(ls->ssl) {
+            // SSL connections are always non-blocking
+            // set socket non blocking
+            int flags;
+            if((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) {
+                flags = 0;
+            }
+            if(fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK)) {
+                perror("Error: acceptor_thread: fcntl");
+                // TODO: error
+            }
+            
             SSL *ssl = SSL_new(ls->ssl->sslctx);
             SSL_set_fd(ssl, clientfd);
-            int ssl_ar = SSL_accept(ssl);
-            if(ssl_ar <= 0) {
-                int error = SSL_get_error(ssl, ssl_ar);
-                char *errstr;
-                switch(error) {
-                    default: errstr = "unknown"; break;
-                    case SSL_ERROR_ZERO_RETURN: errstr = "SSL_ERROR_ZERO_RETURN"; break;
-                    case SSL_ERROR_WANT_READ: errstr = "SSL_ERROR_WANT_READ"; break;
-                    case SSL_ERROR_WANT_WRITE: errstr = "SSL_ERROR_WANT_WRITE"; break;
-                    case SSL_ERROR_WANT_CONNECT: errstr = "SSL_ERROR_WANT_CONNECT"; break;
-                    case SSL_ERROR_WANT_ACCEPT: errstr = "SSL_ERROR_WANT_ACCEPT"; break;
-                    case SSL_ERROR_WANT_X509_LOOKUP: errstr = "SSL_ERROR_WANT_X509_LOOKUP"; break;
-                    case SSL_ERROR_SYSCALL: errstr = "SSL_ERROR_SYSCALL"; break;
-                    case SSL_ERROR_SSL: errstr = "SL_ERROR_SSL"; break;
-                }
-                log_ereport(LOG_VERBOSE, "SSL accept error[%d]: %s", error, errstr);
-                free(conn);
-                conn = NULL;
-                close(clientfd);
-            } else {
-                conn->ssl = ssl;
-                conn->read = connection_ssl_read;
-                conn->write = connection_ssl_write;
-                conn->close = connection_ssl_close;
-            }
+            
+            conn->ssl = ssl;
+            conn->read = connection_ssl_read;
+            conn->write = connection_ssl_write;
+            conn->close = connection_ssl_close;
         } else {
             conn->ssl = NULL;
             conn->read = connection_read;
--- a/src/server/daemon/sessionhandler.c	Wed Jan 10 18:47:37 2018 +0100
+++ b/src/server/daemon/sessionhandler.c	Fri Jan 12 17:54:52 2018 +0100
@@ -183,7 +183,7 @@
     
     // set socket non blocking
     int flags;
-    if (-1 == (flags = fcntl(conn->fd, F_GETFL, 0))) {
+    if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) {
         flags = 0;
     }
     if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) {
@@ -223,7 +223,7 @@
     
     Event *event = malloc(sizeof(Event));
     ZERO(event, sizeof(Event));
-    event->fn = evt_request_input;
+    event->fn = conn->ssl ? evt_request_ssl_accept : evt_request_input;
     event->finish = evt_request_finish;
     event->cookie = io;
     
@@ -237,6 +237,43 @@
     }
 }
 
+int evt_request_ssl_accept(EventHandler *handler, Event *event) {
+    EventHttpIO *io = event->cookie;
+    Connection  *conn = io->request->connection;
+    
+    int ret = SSL_accept(conn->ssl);
+    if(ret <= 0) {
+        int error = SSL_get_error(conn->ssl, ret);
+        char *errstr;
+        switch(error) {
+            default: errstr = "unknown"; break;
+            case SSL_ERROR_WANT_READ: {
+                event->events = EVENT_POLLIN;
+                return 1;
+            }
+            case SSL_ERROR_WANT_WRITE: {
+                event->events = EVENT_POLLOUT;
+                return 1;
+            }
+            case SSL_ERROR_ZERO_RETURN: errstr = "SSL_ERROR_ZERO_RETURN"; break;
+            case SSL_ERROR_WANT_CONNECT: errstr = "SSL_ERROR_WANT_CONNECT"; break;
+            case SSL_ERROR_WANT_ACCEPT: errstr = "SSL_ERROR_WANT_ACCEPT"; break;
+            case SSL_ERROR_WANT_X509_LOOKUP: errstr = "SSL_ERROR_WANT_X509_LOOKUP"; break;
+            case SSL_ERROR_SYSCALL: errstr = "SSL_ERROR_SYSCALL"; break;
+            case SSL_ERROR_SSL: errstr = "SL_ERROR_SSL"; break;
+            
+            log_ereport(LOG_VERBOSE, "SSL accept error[%d]: %s", error, errstr);
+            event->finish = evt_request_error;
+            io->error = 1;
+            return 0;
+        }
+    }
+    
+    // SSL_accept successful, start request input now
+    event->fn = evt_request_input;
+    return evt_request_input(handler, event);
+}
+
 int evt_request_input(EventHandler *handler, Event *event) {    
     EventHttpIO *io = event->cookie;
     HttpParser  *parser  = io->parser;
--- a/src/server/daemon/sessionhandler.h	Wed Jan 10 18:47:37 2018 +0100
+++ b/src/server/daemon/sessionhandler.h	Fri Jan 12 17:54:52 2018 +0100
@@ -125,6 +125,7 @@
 
 void evt_enq_conn(SessionHandler *handler, Connection *conn);
 
+int evt_request_ssl_accept(EventHandler *handler, Event *event);
 int evt_request_input(EventHandler *h, Event *event);
 int evt_request_finish(EventHandler *h, Event *event);
 int evt_request_error(EventHandler *h, Event *event);

mercurial