implement sock_ssl_connect_async (the old sock_ssl_connect exists no more)
authorTero Marttila <terom@fixme.fi>
Thu, 16 Apr 2009 01:20:09 +0300
changeset 139 55b9dcc2b73a
parent 138 a716c621cb90
child 140 aa390e52eda8
implement sock_ssl_connect_async (the old sock_ssl_connect exists no more)
src/irc_net.c
src/log.c
src/log.h
src/nexus.c
src/sock.c
src/sock.h
src/sock_fifo.c
src/sock_gnutls.c
src/sock_gnutls.h
src/sock_internal.h
src/sock_tcp.c
src/sock_test.c
--- a/src/irc_net.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/irc_net.c	Thu Apr 16 01:20:09 2009 +0300
@@ -271,7 +271,7 @@
     
     // trap errors
     if (conn_err)
-        FATAL_ERROR(conn_err, "async TCP connect failed");
+        FATAL_ERROR(conn_err, "async connect failed");
     
     // ok, yay
     if (irc_net_connected(net, sock, &err))
@@ -294,26 +294,22 @@
     TAILQ_INIT(&net->channels);
     LIST_INIT(&net->users);
 
-    // non-async socket connect?
-    if (info->raw_sock || info->use_ssl) {
-        // create the socket
-        if (info->raw_sock) {
-            log_debug("connected using raw socket: %p", info->raw_sock);
+    if (info->raw_sock) {
+        // direct sock_stream connection
+        log_debug("connected using raw socket: %p", info->raw_sock);
 
-            sock = info->raw_sock;
-
-        } else if (info->use_ssl) {
-            log_debug("connecting to [%s]:%s using SSL", info->hostname, info->service);
-
-            // XXX: over-simplified blocking connect
-            if (sock_ssl_connect(&sock, info->hostname, info->service, err))
-                goto error;
-        }
+        sock = info->raw_sock;
 
         // then create the conn right away
         if (irc_net_connected(net, sock, err))
             goto error;
 
+    } else if (info->use_ssl) {
+        log_debug("connecting to [%s]:%s using SSL", info->hostname, info->service);
+
+        if (sock_ssl_connect_async(&sock, info->hostname, info->service, &irc_net_on_connect, net, err))
+            goto error;
+
     } else {
         log_debug("connecting to [%s]:%s", info->hostname, info->service);
             
--- a/src/log.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/log.c	Thu Apr 16 01:20:09 2009 +0300
@@ -114,7 +114,7 @@
     va_end(vargs);
 }
 
-void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
+void _log_err_code (enum log_level level, err_t err, const char *func, const char *format, ...)
 {
     va_list vargs;
 
@@ -124,7 +124,7 @@
     va_end(vargs);
 }
 
-void _log_err_info (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
+void _log_err (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
 {
     va_list vargs;
 
--- a/src/log.h	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/log.h	Thu Apr 16 01:20:09 2009 +0300
@@ -70,13 +70,13 @@
 /**
  * Log a message with the given level, appending the formatted error code name
  */
-void _log_err (enum log_level level, err_t err, const char *func, const char *format, ...)
+void _log_err_code (enum log_level level, err_t err, const char *func, const char *format, ...)
     __attribute__ ((format (printf, 4, 5)));
 
 /**
  * Log a message with the given level, appending the formatted error message
  */
-void _log_err_info (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
+void _log_err (enum log_level level, struct error_info *err, const char *func, const char *format, ...)
     __attribute__ ((format (printf, 4, 5)));
 
 /**
@@ -87,11 +87,16 @@
 
 /**
  * Shorthand for _log_*
+ *
+ * XXX: kill log_err_info, add log_err_code
  */
-#define log_err(err, ...) _log_err(LOG_ERROR, err, __func__, __VA_ARGS__)
-#define log_err_info(err_info, ...) _log_err_info(LOG_ERROR, err_info, __func__, __VA_ARGS__)
+#define log_err(err_code, ...) _log_err_code(LOG_ERROR, err_code, __func__, __VA_ARGS__)
+#define log_err_info(err_info, ...) _log_err(LOG_ERROR, err_info, __func__, __VA_ARGS__)
 #define log_perr(...) _log_perr(LOG_ERROR, __func__, __VA_ARGS__)
 
+#define log_warn_err_code(err_code, ...) _log_err_code(LOG_WARN, err_code, __func__, __VA_ARGS__)
+#define log_warn_err(err_info, ...) _log_err(LOG_WARN, err_info, __func__, __VA_ARGS__)
+
 /**
  * log_fatal + exit failure
  */
@@ -100,12 +105,12 @@
 /**
  * log_err + exit failure
  */
-#define FATAL_ERR(err_code, ...) do { _log_err(LOG_FATAL, err_code, __func__, __VA_ARGS__); exit(EXIT_FAILURE); } while (0)
+#define FATAL_ERR(err_code, ...) do { _log_err_code(LOG_FATAL, err_code, __func__, __VA_ARGS__); exit(EXIT_FAILURE); } while (0)
 
 /**
  * log_err_info + exit failure
  */
-#define FATAL_ERROR(err_info, ...) do { _log_err_info(LOG_FATAL, err_info, __func__, __VA_ARGS__); exit(EXIT_FAILURE); } while (0)
+#define FATAL_ERROR(err_info, ...) do { _log_err(LOG_FATAL, err_info, __func__, __VA_ARGS__); exit(EXIT_FAILURE); } while (0)
 
 /**
  * log_perr + exit failure
--- a/src/nexus.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/nexus.c	Thu Apr 16 01:20:09 2009 +0300
@@ -154,7 +154,7 @@
     while (opt) {
         char *flag = strsep(&opt, ":");
 
-        if (strcmp(flag, "ssl"))
+        if (strcmp(flag, "ssl") == 0)
             info.use_ssl = true;
 
         else
--- a/src/sock.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock.c	Thu Apr 16 01:20:09 2009 +0300
@@ -20,13 +20,15 @@
     return SUCCESS;
 }
 
-void sock_stream_init (struct sock_stream *sock, struct sock_stream_type *type)
+void sock_stream_init (struct sock_stream *sock, struct sock_stream_type *type, sock_stream_connect_cb cb_func, void *cb_arg)
 {
     // be strict
     assert(sock->type == NULL);
 
-    // store type
+    // store 
     sock->type = type;
+    sock->conn_cb_func = cb_func;
+    sock->conn_cb_arg = cb_arg;
 }
 
 int sock_stream_read (struct sock_stream *sock, void *buf, size_t len)
@@ -92,6 +94,22 @@
         sock->cb_info->on_read(sock, sock->cb_arg);
 }
 
+void sock_stream_invoke_conn_cb (struct sock_stream *sock, struct error_info *err, bool direct)
+{
+    if (!direct && sock->type->methods._conn_cb) {
+        // invoke indirectly
+        sock->type->methods._conn_cb(sock, err);
+
+    } else {
+        sock_stream_connect_cb cb_func = sock->conn_cb_func;
+
+        // invoke directly
+        sock->conn_cb_func = NULL;
+        cb_func(sock, err, sock->conn_cb_arg);
+        sock->conn_cb_arg = NULL;
+    }
+}
+
 void sock_stream_release (struct sock_stream *sock)
 {
     sock->type->methods.release(sock);
--- a/src/sock.h	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock.h	Thu Apr 16 01:20:09 2009 +0300
@@ -91,18 +91,19 @@
         sock_stream_connect_cb cb_func, void *cb_arg, struct error_info *err);
 
 /**
- * A simple blocking SSL connect to the given host/service. The connected/handshake'd SSL socket is returned via
- * *sock_ptr. In case of errors, additional error information is stored in *err.
- *
+ * Start a non-blocking SSL connect/handshake to the given host/service. The socket will not yet be connected when the
+ * function returns, but rather, the eventual redyness/failure of the connect/handshake will be indicated later using
+ * the given \a cb_func.
+ * 
  * @param sock_ptr the new sock_stream
  * @param host the hostname to connect to
  * @param service the TCP service name (i.e. port) to connect to
  * @param err returned error info
  *
- * XXX: blocking
  * XXX: doesn't do any certificate verification.
  */
-err_t sock_ssl_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err);
+err_t sock_ssl_connect_async (struct sock_stream **sock_ptr, const char *host, const char *service, 
+        sock_stream_connect_cb cb_func, void *cb_arg, struct error_info *err);
 
 /**
  * A read-only "socket" based on a FIFO, this provides nonblocking read operations by re-opening the FIFO on EOF.
--- a/src/sock_fifo.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_fifo.c	Thu Apr 16 01:20:09 2009 +0300
@@ -133,7 +133,7 @@
         return SET_ERROR(err, ERR_STRDUP);
 
     // init
-    sock_stream_init(FIFO_BASE(fifo), &fifo_stream_type);
+    sock_stream_init(FIFO_BASE(fifo), &fifo_stream_type, NULL, NULL);
     sock_fd_init(FIFO_FD(fifo), -1);
 
     // open the fifo
--- a/src/sock_gnutls.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_gnutls.c	Thu Apr 16 01:20:09 2009 +0300
@@ -1,9 +1,121 @@
 
 #include "sock_gnutls.h"
 
+// XXX: remove
+#include "log.h"
+
 #include <stdlib.h>
 #include <err.h>
 
+/**
+ * Register for events based on the session's gnutls_record_get_direction().
+ */
+static err_t sock_gnutls_ev_enable (struct sock_gnutls *sock, struct error_info *err)
+{
+    int ret;
+
+    // gnutls_record_get_direction tells us what I/O operation gnutls would have required for the last
+    // operation, so we can use that to determine what events to register
+    switch ((ret = gnutls_record_get_direction(sock->session))) {
+        case 0: 
+            // read more data
+            sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_READ); 
+            break;
+        
+        case 1:
+            // write buffer full
+            sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_WRITE);
+            break;
+        
+        default:
+            // random error
+            RETURN_SET_ERROR_EXTRA(err, ERR_GNUTLS_RECORD_GET_DIRECTION, ret);
+    }
+    
+    // ok... wait
+    return SUCCESS;
+}
+
+/**
+ * Our handshake driver. This will execute the next gnutls_handshake step, handling E_AGAIN.
+ *
+ * This updates the sock_gnutls::handshake state internally, as used by sock_gnutls_event_handler.
+ *
+ * @return >0 for finished handshake, 0 for handshake-in-progress, -err_t for errors.
+ */
+static int sock_gnutls_handshake (struct sock_gnutls *sock, struct error_info *err)
+{
+    int ret;
+
+    // perform the handshake
+    if ((ret = gnutls_handshake(sock->session)) < 0 && ret != GNUTLS_E_AGAIN)
+        JUMP_SET_ERROR_EXTRA(err, ERR_GNUTLS_HANDSHAKE, ret);
+    
+    // complete?
+    if (ret == 0) {
+        // update state
+        sock->handshake = false;
+
+        // handshake done
+        return 1;
+
+    } else {
+        // set state, isn't really needed every time, but easier this way
+        sock->handshake = true;
+
+        // re-enable the event for the next iteration
+        return sock_gnutls_ev_enable(sock, err);
+    }
+
+error:
+    return -ERROR_CODE(err);    
+}
+
+/**
+ * Our SOCK_STREAM event handler. Drive the handshake if that's current, otherwise, invoke user callbacks.
+ *
+ * XXX: this is ugly. This sock_stream-level separation doesn't really work that well.
+ */
+static void sock_gnutls_event_handler (int fd, short what, void *arg)
+{
+    struct sock_gnutls *sock = arg;
+    struct error_info err;
+
+    (void) fd;
+    (void) what;
+
+    // are we in the handshake cycle?
+    if (sock->handshake) {
+        RESET_ERROR(&err);
+
+        if (sock_gnutls_handshake(sock, &err) == 0) {
+            // wait for the next handshake step
+        
+        } else if (SOCK_GNUTLS_BASE(sock)->conn_cb_func) {
+            // the async connect process has now completed, either succesfully or not
+            // invoke the user connect callback directly
+            sock_stream_invoke_conn_cb(SOCK_GNUTLS_BASE(sock), ERROR_CODE(&err) ? &err : NULL, true);
+
+        } else {
+            // re-handshake completed, so continue with the sock_stream_callbacks, so the user can call sock_gnutls_read/write
+
+            if (ERROR_CODE(&err))
+                // XXX: bad, since we can't report this directly... we need to let the user call _read/write, and get
+                // the error from there
+                log_warn_err(&err, "sock_gnutls_handshake failed");
+            
+            // continue where we left off
+            sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask);
+        }
+
+    } else {
+        // normal sock_stream operation
+        // gnutls might be able to proceed now, so ask user to try what didn't work before now, using the mask given to
+        // event_enable().
+        sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask);
+    }
+}
+
 static err_t sock_gnutls_read (struct sock_stream *base_sock, void *buf, size_t *len, struct error_info *err)
 {
     struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
@@ -61,65 +173,26 @@
     return SUCCESS;
 }
 
-static void sock_gnutls_event_handler (int fd, short what, void *arg)
-{
-    struct sock_gnutls *sock = arg;
-
-    (void) fd;
-    (void) what;
-    
-    // gnutls might be able to proceed now, so ask user to try what didn't work before now, using the mask given to
-    // event_enable().
-    sock_stream_invoke_callbacks(SOCK_GNUTLS_BASE(sock), sock->ev_mask);
-}
-
 static err_t sock_gnutls_event_init (struct sock_stream *base_sock)
 {
     struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
 
-    err_t err;
+    (void) sock;
 
-    // set nonblocking
-    if ((err = sock_fd_set_nonblock(SOCK_GNUTLS_FD(sock), true)))
-        return err;
-
-    // add ourselves as the event handler
-    if ((err = sock_fd_init_ev(SOCK_GNUTLS_FD(sock), &sock_gnutls_event_handler, sock)))
-        return err;
-
-    // ok
+    // already setup, ok
     return SUCCESS;
 }
 
 static err_t sock_gnutls_event_enable (struct sock_stream *base_sock, short mask)
 {
     struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
-    int ret;
     
     // store the ev_mask. We don't care about it here, because we assume that event_enable is only called once read or
     // write, respectively, return zero. This is really the only case we can handle with gnutls.
     sock->ev_mask = mask;
-
-    // gnutls_record_get_direction tells us what I/O operation gnutls would have required for the last
-    // operation, so we can use that to determine what events to register
-    switch ((ret = gnutls_record_get_direction(sock->session))) {
-        case 0: 
-            // read more data
-            sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_READ); 
-            break;
-        
-        case 1:
-            // write buffer full
-            sock_fd_enable_events(SOCK_GNUTLS_FD(sock), EV_WRITE);
-            break;
-        
-        default:
-            // random error
-            RETURN_SET_ERROR_EXTRA(SOCK_GNUTLS_ERR(sock), ERR_GNUTLS_RECORD_GET_DIRECTION, ret);
-    }
     
-    // ok... wait
-    return SUCCESS;
+    // then wait for the event
+    return sock_gnutls_ev_enable(sock, SOCK_GNUTLS_ERR(sock));
 }
 
 static void sock_gnutls_release (struct sock_stream *base_sock)
@@ -130,6 +203,38 @@
     sock_gnutls_destroy(sock);
 }
 
+/**
+ * Our sock_tcp-invoked connect handler
+ */
+static void sock_gnutls_on_connect (struct sock_stream *base_sock, struct error_info *tcp_err)
+{
+    struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
+    struct error_info err;
+
+    // trap errors to let the user handle them directly
+    if (tcp_err)
+        JUMP_SET_ERROR_INFO(&err, tcp_err);
+    
+    // bind default transport functions (recv/send) to use the TCP fd
+    gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) (long int) SOCK_GNUTLS_FD(sock)->fd);
+
+    // add ourselves as the event handler
+    if ((ERROR_CODE(&err) = sock_fd_init_ev(SOCK_GNUTLS_FD(sock), &sock_gnutls_event_handler, sock)))
+        goto error;
+
+    // start handshake
+    if (sock_gnutls_handshake(sock, &err))
+        // this should complete with SUCCESS if it returns >0
+        goto error;
+
+    // ok, so we wait...
+    return;
+
+error:
+    // tell the user
+    SOCK_GNUTLS_BASE(sock)->conn_cb_func(SOCK_GNUTLS_BASE(sock), &err, SOCK_GNUTLS_BASE(sock)->conn_cb_arg);
+}
+
 /*
  * Our sock_stream_Type
  */
@@ -140,6 +245,7 @@
         .event_init         = &sock_gnutls_event_init,
         .event_enable       = &sock_gnutls_event_enable,
         .release            = &sock_gnutls_release,
+        ._conn_cb           = &sock_gnutls_on_connect,
     },
 };
 
@@ -185,7 +291,8 @@
     return SUCCESS;
 }
 
-err_t sock_ssl_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err)
+err_t sock_ssl_connect_async (struct sock_stream **sock_ptr, const char *host, const char *service, 
+        sock_stream_connect_cb cb_func, void *cb_arg, struct error_info *err)
 {
     struct sock_gnutls *sock = NULL;
     struct sock_gnutls_client_ctx *ctx = &_sock_gnutls_client_ctx;
@@ -195,7 +302,7 @@
         return SET_ERROR(err, ERR_CALLOC);
 
     // initialize base
-    sock_stream_init(SOCK_GNUTLS_BASE(sock), &sock_gnutls_type);
+    sock_stream_init(SOCK_GNUTLS_BASE(sock), &sock_gnutls_type, cb_func, cb_arg);
 
     // initialize client session
     if ((ERROR_EXTRA(err) = gnutls_init(&sock->session, GNUTLS_CLIENT)) < 0)
@@ -210,17 +317,10 @@
         JUMP_SET_ERROR(err, ERR_GNUTLS_CRED_SET);
 
     // TCP connect
-    if (sock_tcp_connect_blocking(SOCK_GNUTLS_TCP(sock), host, service, err))
+    if (sock_tcp_connect_async_begin(SOCK_GNUTLS_TCP(sock), host, service, err))
         goto error;
 
-    // bind default transport functions (recv/send) to use the TCP fd
-    gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) (long int) SOCK_GNUTLS_FD(sock)->fd);
-
-    // perform the handshake
-    if ((ERROR_EXTRA(err) = gnutls_handshake(sock->session)) < 0)
-        JUMP_SET_ERROR(err, ERR_GNUTLS_HANDSHAKE);
-
-    // done
+    // done, wait for the connect to complete
     *sock_ptr = SOCK_GNUTLS_BASE(sock);
 
     return SUCCESS;
--- a/src/sock_gnutls.h	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_gnutls.h	Thu Apr 16 01:20:09 2009 +0300
@@ -54,6 +54,9 @@
 
     /** The current event_enable mask */
     int ev_mask;
+
+    /** Are we running a handshake? */
+    bool handshake;
 };
 
 /**
--- a/src/sock_internal.h	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_internal.h	Thu Apr 16 01:20:09 2009 +0300
@@ -7,6 +7,7 @@
  * internal sock_* interface
  */
 #include "sock.h"
+#include <stdbool.h>
 
 /**
  * General state for all sock_stream's
@@ -40,6 +41,9 @@
     
     /** Release all resources and free the sock_stream */
     void (*release) (struct sock_stream *sock);
+
+    /** The type's connect_cb handler, defaults to just invoke conn_cb_func */
+    void (*_conn_cb) (struct sock_stream *sock, struct error_info *err);
 };
 
 /**
@@ -93,8 +97,10 @@
  *
  * @param sock the new sock_stream
  * @param type the sock_stream_type defining the implementation used
+ * @param cb_func the optional connect_async callback function
+ * @param cb_arg the optional context argument for cb_func
  */
-void sock_stream_init (struct sock_stream *sock, struct sock_stream_type *type);
+void sock_stream_init (struct sock_stream *sock, struct sock_stream_type *type, sock_stream_connect_cb cb_func, void *cb_arg);
 
 /**
  * Invoke the appropriate callbacks for the given EV_* bitmask.
@@ -104,4 +110,13 @@
  */
 void sock_stream_invoke_callbacks (struct sock_stream *sock, short what);
 
+/**
+ * Invoke the sock_stream_conn_cb callback with the given error param.
+ *
+ * This invokes the sock_stream_methods::_conn_cb if present and \a direct is not given, otherwise the callback directly
+ *
+ * @param direct force the conn_cb to be called directly
+ */
+void sock_stream_invoke_conn_cb (struct sock_stream *sock, struct error_info *err, bool direct);
+
 #endif /* SOCK_INTERNAL_H */
--- a/src/sock_tcp.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_tcp.c	Thu Apr 16 01:20:09 2009 +0300
@@ -29,14 +29,14 @@
     },
 };
 
-static err_t sock_tcp_alloc (struct sock_tcp **sock_ptr)
+static err_t sock_tcp_alloc (struct sock_tcp **sock_ptr, sock_stream_connect_cb cb_func, void *cb_arg)
 {
     // alloc
     if ((*sock_ptr = calloc(1, sizeof(**sock_ptr))) == NULL)
         return ERR_CALLOC;
     
     // initialize base with sock_tcp_type
-    sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type);
+    sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type, cb_func, cb_arg);
 
     // init without any fd
     sock_fd_init(SOCK_TCP_FD(*sock_ptr), -1);
@@ -107,7 +107,7 @@
     sock_fd_deinit_ev(SOCK_TCP_FD(sock));
 
     // ok, run callback
-    sock_base->conn_cb_func(sock_base, err, sock_base->conn_cb_arg);
+    sock_stream_invoke_conn_cb(sock_base, err, false);
 }
 
 /**
@@ -304,7 +304,7 @@
     struct sock_tcp *sock;
     
     // allocate
-    if ((ERROR_CODE(err) = sock_tcp_alloc(&sock)))
+    if ((ERROR_CODE(err) = sock_tcp_alloc(&sock, NULL, NULL)))
         return ERROR_CODE(err);
     
     // connect    
@@ -329,13 +329,9 @@
 {
     struct sock_tcp *sock;
     
-    // allocate
-    if ((ERROR_CODE(err) = sock_tcp_alloc(&sock)))
+    // allocate and init
+    if ((ERROR_CODE(err) = sock_tcp_alloc(&sock, cb_func, cb_arg)))
         return ERROR_CODE(err);
-
-    // store the callbacks
-    SOCK_TCP_BASE(sock)->conn_cb_func = cb_func;
-    SOCK_TCP_BASE(sock)->conn_cb_arg = cb_arg;
     
     // connect    
     if (sock_tcp_connect_async_begin(sock, host, service, err))
--- a/src/sock_test.c	Sun Apr 12 23:27:15 2009 +0300
+++ b/src/sock_test.c	Thu Apr 16 01:20:09 2009 +0300
@@ -167,7 +167,7 @@
     assert((sock = calloc(1, sizeof(*sock))));
     
     // initialize base with our sock_stream_type
-    sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type);
+    sock_stream_init(SOCK_TEST_BASE(sock), &sock_test_type, NULL, NULL);
 
     // ok
     return sock;