ssl close connection functions added; destroy ssl connection handler and BIO in canl_...
authorMarcel Poul <marcel.poul@cern.ch>
Mon, 5 Dec 2011 14:07:56 +0000 (14:07 +0000)
committerMarcel Poul <marcel.poul@cern.ch>
Mon, 5 Dec 2011 14:07:56 +0000 (14:07 +0000)
emi.canl.canl-c/Makefile
emi.canl.canl-c/src/canl.c
emi.canl.canl-c/src/canl.h
emi.canl.canl-c/src/canl_cert.c
emi.canl.canl-c/src/canl_err.c
emi.canl.canl-c/src/canl_locl.h
emi.canl.canl-c/src/canl_ssl.c

index 3efd510..2ff8a06 100644 (file)
@@ -16,7 +16,7 @@ COMPILE=libtool --mode=compile ${CC} ${CFLAGS}
 LINK=libtool --mode=link ${CC} ${LDFLAGS}
 INSTALL=libtool --mode=install install
 
-CFLAGS_LIB=-Wall -fPIC -c -g -I${top_srcdir}/src ${LIBCARES_CFLAGS} ${LIBSSL_CFLAGS}
+CFLAGS_LIB=-Wall -pedantic -fPIC -c -g -I${top_srcdir}/src ${LIBCARES_CFLAGS} ${LIBSSL_CFLAGS}
 LFLAGS_LIB=-shared ${LIBCARES_LIBS} ${LIBSSL_LIBS}
 
 CFLAGS_CLI=-Wall -g -I${top_srcdir}/src
index 4a9986c..b9e1f42 100644 (file)
@@ -8,7 +8,7 @@
 
 #define BACKLOG 10 //TODO just for testing - max incoming connections
 
-static int  io_clear(glb_ctx *cc, io_handler *io);
+static void io_destroy(glb_ctx *cc, io_handler *io);
 static int init_io_content(glb_ctx *cc, io_handler *io);
 canl_ctx canl_create_ctx()
 {
@@ -139,7 +139,6 @@ int canl_io_connect(canl_ctx cc, canl_io_handler io, char * host, int port,
     int sock;
     struct sockaddr_in *sa_in = NULL;
     int i = 0;
-    int err_clear = 0;
 
     /*check cc and io*/
     if (!glb_cc) {
@@ -208,9 +207,6 @@ int canl_io_connect(canl_ctx cc, canl_io_handler io, char * host, int port,
 end:
     if (err) {
         update_error(cc, "failed to connect (canl_io_connect)");
-        if ((err_clear = io_clear(glb_cc, io_cc)))
-            update_error(cc, "failed to clean io_handler"
-                   " (canl_io_connect)");
     }
     return err;
 }
@@ -326,34 +322,25 @@ int canl_io_close(canl_ctx cc, canl_io_handler io)
     }
 
     if (!io) {
-        //set_error(ctx->err_msg);
         err = EINVAL;
-        goto end;
+        set_error(glb_cc, err, posix_error,  "invalid io handler"
+                " canl_io_close)");
+        return err;
     }
 
+    return err;
+
     /*ssl close*/
 
     /*set cc and io accordingly*/
-
-end:
-    if (err)
-        update_error(glb_cc, "cannot close connection (canl_io_close)");
-    return err;
 }
-static int io_clear(glb_ctx *cc, io_handler *io)
+static void io_destroy(glb_ctx *cc, io_handler *io)
 {
     io_handler *io_cc = (io_handler*) io;
     glb_ctx *glb_cc = (glb_ctx*) cc;
     int err = 0;
-    /*check cc and io*/
-    if (!cc) {
-        return EINVAL;
-    }
-
-    if (!io) {
-        err = EINVAL;
-        goto end;
-    }
+    unsigned long ssl_err;
+    CANL_ERROR_ORIGIN e_orig = unknown_error;
 
     // delete io_handler content
     if (io_cc->ar) {
@@ -367,12 +354,26 @@ static int io_clear(glb_ctx *cc, io_handler *io)
         free (io_cc->s_addr);
         io_cc->s_addr = NULL;
     }
-
-end:
-    if (err)
-        update_error(glb_cc, "cannot clear io_handle (io_clear)");
-    return err;
-
+    if (io_cc->s_ctx) {
+        /*TODO maybe new function because of BIO_free and SSL_free*/
+        if (io_cc->s_ctx->ssl_io) {
+            SSL_free(io_cc->s_ctx->ssl_io);
+            io_cc->s_ctx->ssl_io = NULL;
+        }
+        if (io_cc->s_ctx->bio_conn) {
+            err = BIO_free(io_cc->s_ctx->bio_conn);
+            /* TODO check it?
+            if (!err) {
+                ssl_err = ERR_peek_error();
+                set_error(io_cc, err, ssl_error, "cannot free BIO"
+                       " (io_destroy)");
+                err = 1;
+            } */
+            io_cc->s_ctx->bio_conn = NULL;
+        }
+    }
+    free (io_cc->s_ctx);
+    io_cc->s_ctx = NULL;
 }
 
 int canl_io_destroy(canl_ctx cc, canl_io_handler io)
@@ -381,27 +382,28 @@ int canl_io_destroy(canl_ctx cc, canl_io_handler io)
     glb_ctx *glb_cc = (glb_ctx*) cc;
     io_handler *io_cc = (io_handler*) io;
     /*check cc and io*/
-    if (!cc) {
+    if (!glb_cc) {
         return EINVAL;
     }
 
-    if (!io) {
-        //set_error(ctx->err_msg);
+    if (!io_cc) {
         err = EINVAL;
-        goto end;
+        set_error(glb_cc, err, posix_error,  "invalid io handler"
+                " canl_io_destroy)");
+        return err;
     }
 
-    err = io_clear(glb_cc, io_cc);
-    if (err)
-        goto end;
+    err = ssl_close(glb_cc, io_cc);
+    if (err <= 0)
+        return err;
+
+    io_destroy(glb_cc, io_cc);
     // delete io itself
     if (io_cc) {
         free (io_cc);
-        io = NULL;
+        io_cc = NULL;
     }
-end:
-    if (err)
-        update_error(glb_cc, "can't destroy io_handle (canl_io_destroy)");
+
     return err;
 }
 
index b6ac2d0..4248a8b 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _CANL_H
 #define _CANL_H
 #include <sys/time.h>
-#include "canl_err.h"
 
 typedef void *canl_io_handler;
 typedef void *canl_ctx;
index 0fe0301..6cc9ac4 100644 (file)
@@ -106,7 +106,7 @@ static int set_key_file(glb_ctx *cc, char *key)
     /*TODO NULL NULL, callback and user data*/
     cc->cert_key->key = PEM_read_PrivateKey(key_file, NULL, NULL, NULL);
     if (!cc->cert_key->key) {
-        ssl_err = ERR_get_error();
+        ssl_err = ERR_peek_error();
         set_error(cc, ssl_err, ssl_error, "error while writing key to context"
                 " (set_key_file)");
         goto end;
index 87b4b7e..f5db3f2 100644 (file)
@@ -103,11 +103,10 @@ int canl_get_error(canl_ctx cc, char  **reason)
     int separ_len = 0;
     const char *msg_pref = "[CANL:MSG] ";
     int msg_pref_len = 0;
+    glb_ctx *ctx = (glb_ctx*) cc;
 
     code_str[0] = '\0';
 
-    glb_ctx *ctx = (glb_ctx*) cc;
-
     /*check cc*/
     if (!ctx) {
         return EINVAL;
index 1cb81d1..68a06b2 100644 (file)
@@ -13,6 +13,7 @@
 #include <openssl/safestack.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include "canl_err.h"
 #include "canl.h"
 
 typedef struct _cert_key_store {
@@ -65,6 +66,7 @@ int ssl_read(glb_ctx *cc, io_handler *io, void *buffer, size_t size,
         struct timeval *tout);
 int ssl_write(glb_ctx *cc, io_handler *io, void *buffer, size_t size, 
         struct timeval *tout);
+int ssl_close(glb_ctx *cc, io_handler *io);
 
 int do_set_ctx_own_cert(glb_ctx *cc, canl_x509 cert, canl_stack_of_x509 chain, 
         canl_pkey key);
index 78f8cd0..e7dac2c 100644 (file)
@@ -1,7 +1,8 @@
 #include "canl_locl.h"
 
-#define SSL_SERVER_METH SSLv3_server_method()
+#define SSL_SERVER_METH SSLv23_server_method()
 #define SSL_CLIENT_METH SSLv3_client_method()
+#define DESTROY_TIMEOUT 10
 
 static int do_ssl_connect( glb_ctx *cc, io_handler *io, struct timeval *timeout);
 static int do_ssl_accept( glb_ctx *cc, io_handler *io, struct timeval *timeout);
@@ -23,8 +24,8 @@ int ssl_server_init(glb_ctx *cc, io_handler *io)
         goto end;
     }
 
-    SSL_load_error_strings();
     SSL_library_init();
+    SSL_load_error_strings();
     //OpenSSL_add_all_algorithms();
     //OpenSSL_add_all_ciphers();
     ERR_clear_error();
@@ -281,6 +282,7 @@ end:
  */
 int do_select(int fd, time_t starttime, int timeout, int wanted)
 {
+    int ret = 0;
     fd_set rset;
     fd_set wset;
 
@@ -292,8 +294,6 @@ int do_select(int fd, time_t starttime, int timeout, int wanted)
     if (wanted == 0 || wanted == SSL_ERROR_WANT_WRITE)
         FD_SET(fd, &wset);
 
-    int ret = 0;
-
     if (timeout != -1) {
         struct timeval endtime;
 
@@ -595,6 +595,71 @@ int ssl_read(glb_ctx *cc, io_handler *io, void *buffer, size_t size, struct time
     return err;
 }
 
+/* ret > 1 if connection does not exist or has been closed before
+ * ret = 0 connection closed successfully (one direction)
+ * ret = 1 connection closed successfully (both directions)
+ * ret < 0 error occured (e.g. timeout reached) */
+int ssl_close(glb_ctx *cc, io_handler *io)
+{
+    int timeout = DESTROY_TIMEOUT;
+    time_t starttime, curtime;
+    int expected = 0, error = 0, ret = 0, ret2 = 0;
+    int fd;
+    unsigned long ssl_err = 0;
+
+    if (!io->s_ctx->ssl_io) {
+        return 2;
+    }
+
+    fd = BIO_get_fd(SSL_get_rbio(io->s_ctx->ssl_io), NULL);
+    curtime = starttime = time(NULL);
+    
+    /* check the shutdown state*/
+    ret = SSL_get_shutdown(io->s_ctx->ssl_io);
+    if (ret & SSL_SENT_SHUTDOWN)
+        if (ret & SSL_RECEIVED_SHUTDOWN)
+            return 1;
+        else
+            return 0;
+    /* TODO check the proper states, maybe also call SSL_shutdown
+    if (ret & SSL_RECEIVED_SHUTDOWN) {
+        return 0;
+    } */
+
+    do {
+        ret = do_select(fd, starttime, timeout, expected);
+       curtime = time(NULL);
+
+       if (ret > 0) {
+           ret2 = SSL_shutdown(io->s_ctx->ssl_io);
+           if (ret2 < 0) {
+                ssl_err = ERR_peek_error();
+               expected = error = SSL_get_error(io->s_ctx->ssl_io, ret2);
+            }
+        }
+    } while (TEST_SELECT(ret, ret2, timeout, curtime, starttime, error));
+
+    if (timeout != -1 && (curtime - starttime >= timeout)){
+        set_error(cc, ETIMEDOUT, posix_error, "Connection stuck"
+                " during ssl shutdown : timeout reached. (ssl_close)");
+        return -1;
+    }
+    /* TODO set_error*/
+    if (ret < 0) {
+        set_error(cc, 0, unknown_error, "Error during SSL"
+                " shutdown: (ssl_close)");
+        return -1;
+    }
+    /* successful shutdown (uni/bi directional)*/
+    if (ret2 == 0 || ret2 == 1)
+        return ret2;
+    else {
+        set_error(cc, ssl_err, ssl_error, "Error during SSL"
+                " shutdown: (ssl_close)");
+        return -1;
+    }
+}
+
 static void dbg_print_ssl_error(int errorcode)
 {
     printf("[DBG CANL] ");