From a4f22127be441c4c158c10fe65916872d99253d2 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Wed, 19 Jan 2022 02:49:47 +0100
Subject: code cleanup

---
 ecp/src/core.c            | 587 ++++++++++++++++++++++++----------------------
 ecp/src/core.h            |  73 ++++--
 ecp/src/dir.c             |   1 +
 ecp/src/dir_srv.c         |  20 +-
 ecp/src/dir_srv.h         |   2 +-
 ecp/src/fe310/transport.h |   2 +
 ecp/src/rbuf.c            | 164 ++++++++++---
 ecp/src/rbuf.h            |  27 ++-
 ecp/src/rbuf_recv.c       |  31 ++-
 ecp/src/rbuf_send.c       | 103 +-------
 ecp/src/timer.c           |  28 +--
 ecp/src/vconn/vconn.c     | 324 +++++++++++++------------
 ecp/src/vconn/vconn.h     |   9 +-
 ecp/test/basic.c          |  12 +-
 ecp/test/client.c         |   8 +-
 ecp/test/dir.c            |  13 +-
 ecp/test/echo.c           |   4 +-
 ecp/test/frag.c           |  12 +-
 ecp/test/init.c           |  15 +-
 ecp/test/init_vconn.c     |  21 +-
 ecp/test/server.c         |   4 +-
 ecp/test/stress.c         |   6 +-
 ecp/test/vc_client.c      |  10 +-
 ecp/test/vc_client_t.c    |  20 +-
 ecp/test/vc_server.c      |  22 +-
 ecp/test/vcs.c            |   8 +-
 ecp/test/voip.c           |   8 +-
 27 files changed, 818 insertions(+), 716 deletions(-)

(limited to 'ecp')

diff --git a/ecp/src/core.c b/ecp/src/core.c
index b4b6055..a8f8f01 100644
--- a/ecp/src/core.c
+++ b/ecp/src/core.c
@@ -8,6 +8,8 @@
 #include "ht.h"
 #endif
 
+#include "dir_srv.h"
+
 int ecp_ctx_init(ECPContext *ctx) {
     int rv;
 
@@ -108,7 +110,7 @@ static int ctable_insert(ECPConnection *conn) {
 #ifdef ECP_WITH_HTABLE
     int i, rv = ECP_OK;
 
-    if (conn->out) {
+    if (ecp_conn_is_outb(conn)) {
         for (i=0; i<ECP_MAX_CONN_KEY; i++) {
             if (conn->key[i].valid) rv = ecp_ht_insert(sock->conn.htable, ecp_cr_dh_pub_get_buf(&conn->key[i].public), conn);
             if (rv) {
@@ -143,7 +145,7 @@ static void ctable_remove(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
 
 #ifdef ECP_WITH_HTABLE
-    if (conn->out) {
+    if (ecp_conn_is_outb(conn)) {
         for (i=0; i<ECP_MAX_CONN_KEY; i++) if (conn->key[i].valid) ecp_ht_remove(sock->conn.htable, ecp_cr_dh_pub_get_buf(&conn->key[i].public));
     } else {
         ECPDHRKeyBucket *remote = &conn->remote;
@@ -171,7 +173,7 @@ static ECPConnection *ctable_search(ECPSocket *sock, unsigned char c_idx, unsign
     if (c_public) {
         for (i=0; i<sock->conn.size; i++) {
             conn = sock->conn.array[i];
-            if (conn->out) {
+            if (ecp_conn_is_outb(conn)) {
                 if ((c_idx < ECP_MAX_CONN_KEY) && conn->key[c_idx].valid && ecp_cr_dh_pub_eq(c_public, &conn->key[c_idx].public))
                     return conn;
             } else {
@@ -183,7 +185,7 @@ static ECPConnection *ctable_search(ECPSocket *sock, unsigned char c_idx, unsign
         /* in case server is not returning client's public key in packet */
         for (i=0; i<sock->conn.size; i++) {
             conn = sock->conn.array[i];
-            if (conn->out && ecp_tr_addr_eq(&conn->node.addr, addr)) return conn;
+            if (ecp_conn_is_outb(conn) && ecp_tr_addr_eq(&conn->node.addr, addr)) return conn;
         }
     }
 
@@ -191,9 +193,7 @@ static ECPConnection *ctable_search(ECPSocket *sock, unsigned char c_idx, unsign
 #endif
 }
 
-int ecp_sock_create(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key) {
-    int rv;
-
+int ecp_sock_init(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key) {
     if (sock == NULL) return ECP_ERR;
     if (ctx == NULL) return ECP_ERR;
 
@@ -208,9 +208,13 @@ int ecp_sock_create(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key) {
     sock->handler[ECP_MTYPE_DIR] = ecp_dir_handle_req;
 #endif
 
-    rv = ecp_dhkey_gen(sock->ctx, &sock->key[sock->key_curr]);
-    if (!rv) rv = ctable_create(&sock->conn, sock->ctx);
+    return ecp_dhkey_gen(sock->ctx, &sock->key[sock->key_curr]);
+}
+
+int ecp_sock_create(ECPSocket *sock) {
+    int rv;
 
+    rv = ctable_create(&sock->conn, sock->ctx);
     if (rv) return rv;
 
     rv = ecp_timer_create(&sock->timer);
@@ -240,13 +244,23 @@ void ecp_sock_destroy(ECPSocket *sock) {
 }
 
 int ecp_sock_open(ECPSocket *sock, void *myaddr) {
+    int rv;
+
+    rv = ecp_sock_create(sock);
+    if (rv) return rv;
+
     return ecp_tr_open(sock, myaddr);
 }
 
 void ecp_sock_close(ECPSocket *sock) {
+    ecp_sock_destroy(sock);
     ecp_tr_close(sock);
 }
 
+ecp_sock_msg_handler_t ecp_sock_get_msg_handler(ECPSocket *sock, unsigned char mtype) {
+    return sock->handler[mtype];
+}
+
 int ecp_sock_dhkey_get_curr(ECPSocket *sock, unsigned char *idx, unsigned char *public) {
     unsigned char _idx;
 
@@ -302,7 +316,7 @@ static int conn_dhkey_new_pair(ECPConnection *conn, ECPDHKey *key) {
 
     conn->key_curr = conn->key_curr == ECP_ECDH_IDX_INV ? 0 : (conn->key_curr+1) % ECP_MAX_CONN_KEY;
 #ifdef ECP_WITH_HTABLE
-    if (conn->out && ecp_conn_is_reg(conn) && conn->key[conn->key_curr].valid) {
+    if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn) && conn->key[conn->key_curr].valid) {
         ecp_ht_remove(sock->conn.htable, ecp_cr_dh_pub_get_buf(&conn->key[conn->key_curr].public));
     }
 #endif
@@ -311,7 +325,7 @@ static int conn_dhkey_new_pair(ECPConnection *conn, ECPDHKey *key) {
     conn->key_idx_map[conn->key_curr] = ECP_ECDH_IDX_INV;
 
 #ifdef ECP_WITH_HTABLE
-    if (conn->out && ecp_conn_is_reg(conn)) {
+    if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn)) {
         int rv;
 
         rv = ecp_ht_insert(sock->conn.htable, ecp_cr_dh_pub_get_buf(&conn->key[conn->key_curr].public), conn);
@@ -326,7 +340,7 @@ static void conn_dhkey_del_pair(ECPConnection *conn, unsigned char idx) {
     ECPSocket *sock = conn->sock;
 
 #ifdef ECP_WITH_HTABLE
-    if (conn->out && ecp_conn_is_reg(conn) && conn->key[idx].valid) {
+    if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn) && conn->key[idx].valid) {
         ecp_ht_remove(sock->conn.htable, ecp_cr_dh_pub_get_buf(&conn->key[idx].public));
     }
 #endif
@@ -364,7 +378,7 @@ static int conn_dhkey_new_pub_remote(ECPConnection *conn, unsigned char idx, uns
     if ((remote->key_idx_map[idx] != ECP_ECDH_IDX_INV) && ecp_cr_dh_pub_eq(public, &remote->key[remote->key_idx_map[idx]].public)) return ECP_ERR_ECDH_KEY_DUP;
 
 #ifdef ECP_WITH_HTABLE
-    if (!conn->out && ecp_conn_is_reg(conn) && (remote->key[new].idx != ECP_ECDH_IDX_INV)) {
+    if (ecp_conn_is_inb(conn) && ecp_conn_is_reg(conn) && (remote->key[new].idx != ECP_ECDH_IDX_INV)) {
         ecp_ht_remove(sock->conn.htable, ecp_cr_dh_pub_get_buf(&remote->key[new].public));
     }
 #endif
@@ -376,7 +390,7 @@ static int conn_dhkey_new_pub_remote(ECPConnection *conn, unsigned char idx, uns
     remote->key_curr = new;
 
 #ifdef ECP_WITH_HTABLE
-    if (!conn->out && ecp_conn_is_reg(conn)) {
+    if (ecp_conn_is_inb(conn) && ecp_conn_is_reg(conn)) {
         int rv;
 
         rv = ecp_ht_insert(sock->conn.htable, ecp_cr_dh_pub_get_buf(&remote->key[new].public), conn);
@@ -395,7 +409,7 @@ static int conn_shsec_get(ECPConnection *conn, unsigned char s_idx, unsigned cha
         ECPDHKey *priv = NULL;
         ecp_dh_public_t *public_p = NULL;
 
-        if (conn->out) {
+        if (ecp_conn_is_outb(conn)) {
             public_p = &conn->node.public;
             priv = conn_dhkey_get(conn, c_idx);
         } else {
@@ -414,8 +428,8 @@ static int conn_shsec_get(ECPConnection *conn, unsigned char s_idx, unsigned cha
         if ((priv == NULL) || !priv->valid) return ECP_ERR_ECDH_IDX;
         ecp_cr_dh_shsec(shsec, public_p, &priv->private);
     } else {
-        unsigned char l_idx = conn->out ? c_idx : s_idx;
-        unsigned char r_idx = conn->out ? s_idx : c_idx;
+        unsigned char l_idx = ecp_conn_is_outb(conn) ? c_idx : s_idx;
+        unsigned char r_idx = ecp_conn_is_outb(conn) ? s_idx : c_idx;
         ECPDHShared *shared = NULL;
 
         if ((l_idx >= ECP_MAX_SOCK_KEY) || (r_idx >= ECP_MAX_SOCK_KEY)) return ECP_ERR_ECDH_IDX;
@@ -443,8 +457,8 @@ static int conn_shsec_get(ECPConnection *conn, unsigned char s_idx, unsigned cha
 }
 
 static int conn_shsec_set(ECPConnection *conn, unsigned char s_idx, unsigned char c_idx, ecp_aead_key_t *shsec) {
-    unsigned char l_idx = conn->out ? c_idx : s_idx;
-    unsigned char r_idx = conn->out ? s_idx : c_idx;
+    unsigned char l_idx = ecp_conn_is_outb(conn) ? c_idx : s_idx;
+    unsigned char r_idx = ecp_conn_is_outb(conn) ? s_idx : c_idx;
     ECPDHShared *shared = NULL;
 
     if ((l_idx >= ECP_MAX_SOCK_KEY) || (r_idx >= ECP_MAX_SOCK_KEY)) return ECP_ERR_ECDH_IDX;
@@ -459,8 +473,8 @@ static int conn_shsec_set(ECPConnection *conn, unsigned char s_idx, unsigned cha
     return ECP_OK;
 }
 
-int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
-    int i, rv;
+int ecp_conn_init(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
+    int i;
 
     if (conn == NULL) return ECP_ERR;
     if (sock == NULL) return ECP_ERR;
@@ -469,6 +483,8 @@ int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
 
     if (ctype >= ECP_MAX_CTYPE) return ECP_ERR_MAX_CTYPE;
 
+    ecp_conn_set_new(conn);
+    conn->sock = sock;
     conn->type = ctype;
     conn->key_curr = ECP_ECDH_IDX_INV;
     conn->key_idx_curr = ECP_ECDH_IDX_INV;
@@ -480,7 +496,11 @@ int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
     }
     memset(conn->remote.key_idx_map, ECP_ECDH_IDX_INV, sizeof(conn->remote.key_idx_map));
 
-    conn->sock = sock;
+    return ECP_OK;
+}
+
+int ecp_conn_create(ECPConnection *conn) {
+    int rv;
 
 #ifdef ECP_WITH_PTHREAD
     rv = pthread_mutex_init(&conn->mutex, NULL);
@@ -496,24 +516,78 @@ void ecp_conn_destroy(ECPConnection *conn) {
 #endif
 }
 
+int ecp_conn_create_inb(ECPConnection *conn, ECPConnection *parent, unsigned char c_idx, unsigned char *public) {
+    ECPContext *ctx = conn->sock->ctx;
+    int rv;
+
+    rv = ecp_conn_create(conn);
+    if (rv) return rv;
+
+    conn->refcount = 1;
+    conn->parent = parent;
+    conn->pcount = parent ? parent->pcount+1 : 0;
+
+    rv = ctx->rng(&conn->seq_out, sizeof(conn->seq_out));
+    if (!rv) rv = conn_dhkey_new_pub_remote(conn, c_idx, public);
+
+    if (rv) {
+        ecp_conn_destroy(conn);
+        return rv;
+    }
+
+    return ECP_OK;
+}
+
+int ecp_conn_create_outb(ECPConnection *conn, ECPNode *node) {
+    ECPContext *ctx = conn->sock->ctx;
+    ECPDHKey key;
+    int rv;
+
+    if (node == NULL) return ECP_ERR;
+
+    rv = ecp_conn_create(conn);
+    if (rv) return rv;
+
+    ecp_conn_set_outb(conn);
+    conn->node = *node;
+    rv = ecp_dhkey_gen(ctx, &key);
+    if (!rv) rv = ctx->rng(conn->nonce, ECP_AEAD_SIZE_NONCE);
+    if (!rv) rv = ctx->rng(&conn->seq_out, sizeof(conn->seq_out));
+
+    if (!rv) rv = conn_dhkey_new_pair(conn, &key);
+    if (!rv) rv = conn_dhkey_new_pub_local(conn, conn->key_curr);
+
+    if (rv) {
+        ecp_conn_destroy(conn);
+        return rv;
+    }
+
+    return ECP_OK;
+}
+
+int ecp_conn_insert(ECPConnection *conn) {
+    ecp_conn_clr_new(conn);
+    return ecp_conn_register(conn);
+}
+
 int ecp_conn_register(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
     int rv;
 
-    conn->flags |= ECP_CONN_FLAG_REG;
+    ecp_conn_set_reg(conn);
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&sock->conn.mutex);
 #endif
     rv = ctable_insert(conn);
-    if (rv) conn->flags &= ~ECP_CONN_FLAG_REG;
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&sock->conn.mutex);
 #endif
+    if (rv) ecp_conn_clr_reg(conn);
 
     return rv;
 }
 
-void ecp_conn_unregister(ECPConnection *conn) {
+void ecp_conn_unregister(ECPConnection *conn, unsigned short *refcount) {
     ECPSocket *sock = conn->sock;
 
 #ifdef ECP_WITH_PTHREAD
@@ -522,45 +596,31 @@ void ecp_conn_unregister(ECPConnection *conn) {
 #endif
     if (ecp_conn_is_reg(conn)) {
         ctable_remove(conn);
-        conn->flags &= ~ECP_CONN_FLAG_REG;
+        ecp_conn_clr_reg(conn);
     }
+    if (refcount) *refcount = conn->refcount;
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&conn->mutex);
     pthread_mutex_unlock(&sock->conn.mutex);
 #endif
 }
 
-/* initializes outbound connection */
-int ecp_conn_set_remote(ECPConnection *conn, ECPNode *node) {
-    ECPDHKey key;
-    ECPContext *ctx = conn->sock->ctx;
-    int rv;
-
-    if (node == NULL) return ECP_ERR;
-
-    conn->out = 1;
-    conn->node = *node;
-    rv = ecp_dhkey_gen(ctx, &key);
-    if (!rv) rv = ctx->rng(conn->nonce, ECP_AEAD_SIZE_NONCE);
-    if (!rv) rv = ctx->rng(&conn->seq_out, sizeof(conn->seq_out));
-
-    if (!rv) rv = conn_dhkey_new_pair(conn, &key);
-    if (!rv) rv = conn_dhkey_new_pub_local(conn, conn->key_curr);
-    if (!rv) rv = ecp_conn_register(conn);
-
-    return rv;
-}
-
 int ecp_conn_get_dirlist(ECPConnection *conn, ECPNode *node) {
     int rv;
     ssize_t _rv;
 
-    rv = ecp_conn_set_remote(conn, node);
+    rv = ecp_conn_create_outb(conn, node);
     if (rv) return rv;
 
+    rv = ecp_conn_insert(conn);
+    if (rv) {
+        ecp_conn_destroy(conn);
+        return rv;
+    }
+
     _rv = ecp_conn_send_dir(conn);
     if (_rv < 0) {
-        ecp_conn_unregister(conn);
+        ecp_conn_close(conn);
         return _rv;
     }
 
@@ -571,59 +631,48 @@ int ecp_conn_open(ECPConnection *conn, ECPNode *node) {
     int rv;
     ssize_t _rv;
 
-    rv = ecp_conn_set_remote(conn, node);
+    rv = ecp_conn_create_outb(conn, node);
     if (rv) return rv;
 
+    rv = ecp_conn_insert(conn);
+    if (rv) {
+        ecp_conn_destroy(conn);
+        return rv;
+    }
+
     _rv = ecp_conn_send_kget(conn);
     if (_rv < 0) {
-        ecp_conn_unregister(conn);
+        ecp_conn_close(conn);
         return _rv;
     }
 
     return ECP_OK;
 }
 
-int ecp_conn_close(ECPConnection *conn, ecp_cts_t timeout) {
-    ECPSocket *sock = conn->sock;
-    int refcount = 0;
+void _ecp_conn_close(ECPConnection *conn) {
+    ECPContext *ctx = conn->sock->ctx;
 
-    ecp_conn_unregister(conn);
-    ecp_timer_remove(conn);
+    if (ecp_conn_is_inb(conn) && conn->parent) {
+        ecp_conn_refcount_dec(conn->parent);
+    }
 
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn->mutex);
-    refcount = conn->refcount;
-    pthread_mutex_unlock(&conn->mutex);
+    ecp_conn_destroy(conn);
 
-    if (timeout && refcount) {
-        ecp_tm_sleep_ms(timeout);
-        pthread_mutex_lock(&conn->mutex);
-        refcount = conn->refcount;
-        pthread_mutex_unlock(&conn->mutex);
-    }
+    if (ecp_conn_is_inb(conn) && ctx->conn_free) ctx->conn_free(conn);
+}
 
-    if (refcount) return ECP_ERR_TIMEOUT;
-#endif
+int ecp_conn_close(ECPConnection *conn) {
+    unsigned short refcount = 0;
+    ecp_conn_close_t handler;
 
-    if (conn->out) {
-        ecp_conn_close_t handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->conn_close : NULL;
-        if (handler) handler(conn);
-    } else {
-        ecp_conn_destroy_t handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->conn_destroy : NULL;
-        if (handler) handler(conn);
-        if (conn->parent) {
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&conn->parent->mutex);
-#endif
-            conn->parent->refcount--;
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&conn->parent->mutex);
-#endif
-        }
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-    }
+    ecp_conn_unregister(conn, &refcount);
+    ecp_timer_remove(conn);
+    handler = ecp_conn_get_close_handler(conn);
+    if (handler) handler(conn);
+
+    if (refcount) return ECP_ERR_BUSY;
 
+    _ecp_conn_close(conn);
     return ECP_OK;
 }
 
@@ -655,7 +704,7 @@ int ecp_conn_reset(ECPConnection *conn) {
     if (!rv) rv = conn_dhkey_new_pub_local(conn, conn->key_curr);
     if (!rv) rv = ctx->rng(conn->nonce, ECP_AEAD_SIZE_NONCE);
     if (!rv) rv = ctx->rng(&conn->seq_out, sizeof(conn->seq_out));
-    conn->flags &= ~ECP_CONN_FLAG_OPEN;
+    ecp_conn_clr_open(conn);
 
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&conn->mutex);
@@ -664,6 +713,33 @@ int ecp_conn_reset(ECPConnection *conn) {
     return rv;
 }
 
+void ecp_conn_refcount_inc(ECPConnection *conn) {
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_lock(&conn->mutex);
+#endif
+    conn->refcount++;
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_unlock(&conn->mutex);
+#endif
+}
+
+void ecp_conn_refcount_dec(ECPConnection *conn) {
+    int is_reg;
+    unsigned short refcount;
+
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_lock(&conn->mutex);
+#endif
+    conn->refcount--;
+    refcount = conn->refcount;
+    is_reg = ecp_conn_is_reg(conn);
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_unlock(&conn->mutex);
+#endif
+
+    if (!is_reg && (refcount == 0)) _ecp_conn_close(conn);
+}
+
 int ecp_conn_handler_init(ECPConnHandler *handler) {
     memset(handler, 0, sizeof(ECPConnHandler));
     handler->msg[ECP_MTYPE_OPEN] = ecp_conn_handle_open;
@@ -677,10 +753,20 @@ int ecp_conn_handler_init(ECPConnHandler *handler) {
     handler->msg[ECP_MTYPE_RBFLUSH] = ecp_rbuf_handle_flush;
     handler->msg[ECP_MTYPE_RBFLUSH_PTS] = ecp_rbuf_handle_flush_pts;
 #endif
-    handler->conn_open = ecp_conn_send_open;
     return ECP_OK;
 }
 
+ecp_conn_msg_handler_t ecp_conn_get_msg_handler(ECPConnection *conn, unsigned char mtype) {
+    ECPContext *ctx = conn->sock->ctx;
+    return ctx->handler[conn->type] ? ctx->handler[conn->type]->msg[mtype] : NULL;
+}
+
+ecp_conn_close_t ecp_conn_get_close_handler(ECPConnection *conn) {
+    ECPContext *ctx = conn->sock->ctx;
+    return ctx->handler[conn->type] ? ctx->handler[conn->type]->conn_close : NULL;
+}
+
+
 int ecp_conn_dhkey_new(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
     ECPDHKey new_key;
@@ -836,42 +922,64 @@ ssize_t ecp_conn_send_dir(ECPConnection *conn) {
     return ecp_timer_send(conn, _conn_send_dir, ECP_MTYPE_DIR_REP, 3, 500);
 }
 
-ssize_t ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
-    int is_open;
+ssize_t _ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b, int *was_open) {
+    ssize_t rv;
+    int _rv;
+
+    if (mtype & ECP_MTYPE_FLAG_REP) {
+        int is_open;
+
+        if (ecp_conn_is_inb(conn)) return ECP_ERR;
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn->mutex);
+        pthread_mutex_lock(&conn->mutex);
 #endif
-    is_open = ecp_conn_is_open(conn);
-    if (!is_open && (size >= 0)) conn->flags |= ECP_CONN_FLAG_OPEN;
+        is_open = ecp_conn_is_open(conn);
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
+        pthread_mutex_unlock(&conn->mutex);
 #endif
 
-    if (mtype & ECP_MTYPE_FLAG_REP) {
-        if (!conn->out) return ECP_ERR;
-
         if (is_open && size == ECP_ERR_TIMEOUT) {
-            int rv;
-
-            rv = ecp_conn_reset(conn);
-            if (rv) return rv;
+            _rv = ecp_conn_reset(conn);
+            if (_rv) return _rv;
             return 0;
         }
 
         if (size < 0) return size;
-        return 0;
-    } else {
-        if (size < 0) return size;
-        if (size < 1) return ECP_ERR;
-        if (conn->out) return ECP_ERR;
 
+        if (was_open) *was_open = is_open;
+
+        if (!is_open) {
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_lock(&conn->mutex);
+#endif
+            ecp_conn_set_open(conn);
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_unlock(&conn->mutex);
+#endif
+        }
+
+        rv = 0;
+    } else {
         ECPBuffer packet;
         ECPBuffer payload;
         unsigned char pkt_buf[ECP_SIZE_PKT_BUF(0, ECP_MTYPE_OPEN_REP, conn)];
         unsigned char pld_buf[ECP_SIZE_PLD_BUF(0, ECP_MTYPE_OPEN_REP, conn)];
-        unsigned char ctype = 0;
-        ssize_t _rv;
+        unsigned char ctype;
+        int is_new;
+
+        if (size < 0) return size;
+        if (size < 1) return ECP_ERR;
+        if (ecp_conn_is_outb(conn)) return ECP_ERR;
+
+        is_new = ecp_conn_is_new(conn);
+        if (is_new) {
+            ecp_conn_set_open(conn);
+            _rv = ecp_conn_insert(conn);
+            if (_rv) return rv;
+        }
+
+        if (was_open) *was_open = !is_new;
 
         packet.buffer = pkt_buf;
         packet.size = ECP_SIZE_PKT_BUF(0, ECP_MTYPE_OPEN_REP, conn);
@@ -880,20 +988,27 @@ ssize_t ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char m
 
         ctype = msg[0];
         ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_OPEN_REP);
-        _rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_OPEN_REP), 0);
+        rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_OPEN_REP), 0);
 
-        return 1;
+        rv = 1;
     }
-    return ECP_ERR;
+
+    return rv;
 }
 
-ssize_t ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+ssize_t ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    return _ecp_conn_handle_open(conn, seq, mtype, msg, size, b, NULL);
+}
+
+ssize_t _ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b, ecp_conn_open_t conn_open) {
+    ssize_t rv;
+    int _rv;
+
     if (mtype & ECP_MTYPE_FLAG_REP) {
         ECPContext *ctx = conn->sock->ctx;
-        int rv;
         int is_open;
 
-        if (!conn->out) return ECP_ERR;
+        if (ecp_conn_is_inb(conn)) return ECP_ERR;
 
 #ifdef ECP_WITH_PTHREAD
         pthread_mutex_lock(&conn->mutex);
@@ -904,37 +1019,32 @@ ssize_t ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char m
 #endif
 
         if ((size < 0) && !is_open) {
-            ecp_conn_handler_msg_t handler = ctx->handler[conn->type] ? ctx->handler[conn->type]->msg[ECP_MTYPE_OPEN] : NULL;
+            ecp_conn_msg_handler_t handler;
+
+            handler = ecp_conn_get_msg_handler(conn, ECP_MTYPE_OPEN);
             return handler ? handler(conn, seq, mtype, msg, size, b) : size;
         }
 
         if (size < 0) return size;
         if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
 
-        rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
-        if (!rv && !is_open) {
-            ecp_conn_open_t conn_open = ctx->handler[conn->type] ? ctx->handler[conn->type]->conn_open : NULL;
-            if (conn_open) {
-                ssize_t _rv;
+        _rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
+        if (_rv) return _rv;
 
-                _rv = conn_open(conn);
-                if (_rv < 0) rv = _rv;
-            }
+        if (!is_open && conn_open) {
+            rv = conn_open(conn);
         }
-        if (rv) return rv;
 
-        return ECP_ECDH_SIZE_KEY+1;
+        rv = ECP_ECDH_SIZE_KEY+1;
     } else {
-        if (conn->out) return ECP_ERR;
-        if (size < 0) return size;
-
         ECPBuffer packet;
         ECPBuffer payload;
         unsigned char pkt_buf[ECP_SIZE_PKT_BUF(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, conn)];
         unsigned char pld_buf[ECP_SIZE_PLD_BUF(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, conn)];
         unsigned char *buf;
-        int rv;
-        ssize_t _rv;
+
+        if (ecp_conn_is_outb(conn)) return ECP_ERR;
+        if (size < 0) return size;
 
         packet.buffer = pkt_buf;
         packet.size = ECP_SIZE_PKT_BUF(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, conn);
@@ -944,86 +1054,58 @@ ssize_t ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char m
         ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_KGET_REP);
         buf= ecp_pld_get_buf(payload.buffer, payload.size);
 
-        rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
-        if (rv) return rv;
-        _rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP), 0);
+        _rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
+        if (_rv) return _rv;
+        rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP), 0);
 
-        return 0;
+        rv = 0;
     }
-    return ECP_ERR;
+
+    return rv;
+}
+
+ssize_t ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    return _ecp_conn_handle_kget(conn, seq, mtype, msg, size, b, ecp_conn_send_open);
 }
 
 ssize_t ecp_conn_handle_kput(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    ssize_t rv;
+    int _rv;
+
     if (size < 0) return size;
 
     if (mtype & ECP_MTYPE_FLAG_REP) {
-        if (!conn->out) return ECP_ERR;
-        return 0;
-    } else {
-        if (conn->out) return ECP_ERR;
-        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
+        if (ecp_conn_is_inb(conn)) return ECP_ERR;
 
+        rv = 0;
+    } else {
         ECPBuffer packet;
         ECPBuffer payload;
         unsigned char pkt_buf[ECP_SIZE_PKT_BUF(0, ECP_MTYPE_KPUT_REP, conn)];
         unsigned char pld_buf[ECP_SIZE_PLD_BUF(0, ECP_MTYPE_KPUT_REP, conn)];
-        int rv;
-        ssize_t _rv;
+
+        if (ecp_conn_is_outb(conn)) return ECP_ERR;
+        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
 
         packet.buffer = pkt_buf;
         packet.size = ECP_SIZE_PKT_BUF(0, ECP_MTYPE_KPUT_REP, conn);
         payload.buffer = pld_buf;
         payload.size = ECP_SIZE_PLD_BUF(0, ECP_MTYPE_KPUT_REP, conn);
 
-        rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
-        if (rv) return rv;
+        _rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
+        if (_rv) return _rv;
 
         ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_KPUT_REP);
-        _rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_KPUT_REP), 0);
+        rv = ecp_pld_send(conn, &packet, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_KPUT_REP), 0);
 
-        return ECP_ECDH_SIZE_KEY+1;
+        rv = ECP_ECDH_SIZE_KEY+1;
     }
-    return ECP_ERR;
-}
-
-#ifdef ECP_MEM_TINY
-/* Memory limited version */
-
-ssize_t ecp_conn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
-    if (size < 0) return size;
-    if (b == NULL) return ECP_ERR;
-    if (b->packet->buffer == NULL) return ECP_ERR;
-
-    memcpy(b->packet->buffer, msg, size);
-    return ecp_pkt_handle(conn->sock, NULL, conn, b, size);
-}
-
-#else
-
-ssize_t ecp_conn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
-    if (size < 0) return size;
-    if (b == NULL) return ECP_ERR;
-
-    ECP2Buffer b2;
-    ECPBuffer packet;
-    ECPBuffer payload;
-    unsigned char pld_buf[ECP_MAX_PLD];
 
-    b2.packet = &packet;
-    b2.payload = &payload;
-
-    packet.buffer = msg;
-    packet.size = b->payload->size - (msg - b->payload->buffer);
-    payload.buffer = pld_buf;
-    payload.size = ECP_MAX_PLD;
-
-    return ecp_pkt_handle(conn->sock, NULL, conn, &b2, size);
+    return rv;
 }
 
-#endif
-
 ssize_t ecp_conn_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs) {
-    ecp_conn_handler_msg_t handler = NULL;
+    ecp_conn_msg_handler_t handler;
     unsigned char mtype = 0;
     unsigned char *content = NULL;
     size_t rem_size = msg_size;
@@ -1039,8 +1121,9 @@ ssize_t ecp_conn_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char *m
 
         if (mtype & ECP_MTYPE_FLAG_FRAG) {
 #ifdef ECP_WITH_RBUF
-            if (conn->rbuf.recv && conn->rbuf.recv->frag_iter) {
-                _rv = ecp_msg_defrag(conn->rbuf.recv->frag_iter, seq, mtype, msg, msg_size, &msg, &rem_size);
+            ECPFragIter *iter = ecp_rbuf_get_frag_iter(conn);
+            if (iter) {
+                _rv = ecp_msg_defrag(iter, seq, mtype, msg, msg_size, &msg, &rem_size);
                 if (_rv == ECP_ITER_NEXT) break;
                 if (_rv < 0) return _rv;
             } else {
@@ -1053,7 +1136,7 @@ ssize_t ecp_conn_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char *m
         if (content == NULL) return ECP_ERR_MIN_MSG;
         rem_size -= content - msg;
 
-        handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[mtype & ECP_MTYPE_MASK] : NULL;
+        handler = ecp_conn_get_msg_handler(conn, mtype & ECP_MTYPE_MASK);
         if (handler) {
             rv = handler(conn, seq, mtype, content, rem_size, bufs);
             if (rv < 0) return rv;
@@ -1070,84 +1153,44 @@ ssize_t ecp_conn_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char *m
     return msg_size;
 }
 
-int ecp_sock_handle_open(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
+ssize_t ecp_sock_handle_open(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
     ECPConnection *conn = NULL;
-    ecp_conn_create_t handle_create = NULL;
-    ecp_conn_destroy_t handle_destroy = NULL;
-    unsigned char ctype;
     unsigned char c_idx = pkt_meta->c_idx;
-    unsigned char s_idx = pkt_meta->s_idx;
+    unsigned char ctype;
     int rv;
 
+    if (msg_size < 0) return msg_size;
     if (msg_size < 1) return ECP_ERR;
 
     ctype = msg[0];
 
-    conn = sock->ctx->conn_alloc ? sock->ctx->conn_alloc(ctype) : NULL;
+    conn = sock->ctx->conn_alloc ? sock->ctx->conn_alloc(sock, ctype) : NULL;
     if (conn == NULL) return ECP_ERR_ALLOC;
 
-    rv = ecp_conn_create(conn, sock, ctype);
+    rv = ecp_conn_create_inb(conn, parent, c_idx, pkt_meta->public);
     if (rv) {
         if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
         return rv;
     }
-    rv = sock->ctx->rng(&conn->seq_out, sizeof(conn->seq_out));
-    if (rv) {
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
-
-    conn->refcount = 1;
-    conn->parent = parent;
-    conn->pcount = parent ? parent->pcount+1 : 0;
-    handle_create = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->conn_create : NULL;
-    handle_destroy = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->conn_destroy : NULL;
-
-    if (handle_create) rv = handle_create(conn, msg+1, msg_size-1);
-    if (rv) {
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
-
-    rv = conn_dhkey_new_pub_remote(conn, c_idx, ecp_cr_dh_pub_get_buf(&pkt_meta->public));
-    if (rv) {
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
-
-    rv = ecp_conn_register(conn);
-    if (rv) {
-        if (handle_destroy) handle_destroy(conn);
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
 
     if (parent) {
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&parent->mutex);
-#endif
-        parent->refcount++;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&parent->mutex);
-#endif
+        ecp_conn_refcount_inc(parent);
     }
 
     *_conn = conn;
-    return ECP_OK;
+    return 1;
 }
 
-int ecp_sock_handle_kget(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
+ssize_t ecp_sock_handle_kget(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
     ECPBuffer packet;
     ECPBuffer payload;
     unsigned char pkt_buf[ECP_SIZE_PKT_BUF_TR(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, parent)];
     unsigned char pld_buf[ECP_SIZE_PLD_BUF_TR(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, parent)];
     unsigned char *buf;
-    int rv;
-    ssize_t _rv;
+    ssize_t rv;
+    int _rv;
+
+    if (msg_size < 0) return msg_size;
 
     packet.buffer = pkt_buf;
     packet.size = ECP_SIZE_PKT_BUF_TR(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP, parent);
@@ -1157,13 +1200,13 @@ int ecp_sock_handle_kget(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *paren
     ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_KGET_REP);
     buf = ecp_pld_get_buf(payload.buffer, payload.size);
 
-    rv = ecp_sock_dhkey_get_curr(sock, buf, buf+1);
-    if (rv) return rv;
+    _rv = ecp_sock_dhkey_get_curr(sock, buf, buf+1);
+    if (_rv) return _rv;
 
-    _rv = ecp_pld_send_tr(sock, addr, parent, &packet, pkt_meta, &payload, ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP), 0);
-    if (_rv < 0) return _rv;
+    rv = ecp_pld_send_tr(sock, addr, parent, &packet, pkt_meta, &payload, ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_KGET_REP), 0);
+    if (rv < 0) return rv;
 
-    return ECP_OK;
+    return msg_size;
 }
 
 
@@ -1179,7 +1222,7 @@ ssize_t _ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, ECPPk
     s_idx = pkt_meta->s_idx & 0x0F;
     c_idx = pkt_meta->c_idx & 0x0F;
     packet[ECP_SIZE_PROTO] = (s_idx << 4) | c_idx;
-    ecp_cr_dh_pub_to_buf(packet+ECP_SIZE_PROTO+1, &pkt_meta->public);
+    memcpy(packet+ECP_SIZE_PROTO+1, pkt_meta->public, ECP_ECDH_SIZE_KEY);
     memcpy(packet+ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY, pkt_meta->nonce, ECP_AEAD_SIZE_NONCE);
 
     payload[0] = (pkt_meta->seq & 0xFF000000) >> 24;
@@ -1212,14 +1255,14 @@ ssize_t _ecp_pack_conn(ECPConnection *conn, unsigned char *packet, size_t pkt_si
     pthread_mutex_lock(&conn->mutex);
 #endif
     if (s_idx == ECP_ECDH_IDX_INV) {
-        if (conn->out) {
+        if (ecp_conn_is_outb(conn)) {
             if (conn->remote.key_curr != ECP_ECDH_IDX_INV) s_idx = conn->remote.key[conn->remote.key_curr].idx;
         } else {
             if (conn->key_idx_curr != ECP_ECDH_IDX_INV) s_idx = conn->key_idx[conn->key_idx_curr];
         }
     }
     if (c_idx == ECP_ECDH_IDX_INV) {
-        if (conn->out) {
+        if (ecp_conn_is_outb(conn)) {
             if (conn->key_idx_curr != ECP_ECDH_IDX_INV) c_idx = conn->key_idx[conn->key_idx_curr];
         } else {
             if (conn->remote.key_curr != ECP_ECDH_IDX_INV) c_idx = conn->remote.key[conn->remote.key_curr].idx;
@@ -1228,7 +1271,7 @@ ssize_t _ecp_pack_conn(ECPConnection *conn, unsigned char *packet, size_t pkt_si
     rv = conn_shsec_get(conn, s_idx, c_idx, &pkt_meta.shsec);
     if (!rv) memcpy(pkt_meta.nonce, conn->nonce, sizeof(pkt_meta.nonce));
     if (!rv) {
-        if (conn->out) {
+        if (ecp_conn_is_outb(conn)) {
             ECPDHKey *key = conn_dhkey_get(conn, c_idx);
 
             if ((key == NULL) || !key->valid) rv = ECP_ERR_ECDH_IDX;
@@ -1248,10 +1291,7 @@ ssize_t _ecp_pack_conn(ECPConnection *conn, unsigned char *packet, size_t pkt_si
 
 #ifdef ECP_WITH_RBUF
             if (conn->rbuf.send) {
-                unsigned char mtype;
-
-                rv = ecp_pld_get_type(payload, pld_size, &mtype);
-                if (!rv) rv = ecp_rbuf_pkt_prep(conn->rbuf.send, si, mtype);
+                rv = ecp_rbuf_set_seq(conn, si, payload, pld_size);
             }
 #endif
 
@@ -1332,7 +1372,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, ECP
 #endif
 
     conn = ctable_search(sock, c_idx, public_buf, NULL);
-    if (conn && !conn->out && (s_idx == ECP_ECDH_IDX_PERMA)) conn = NULL;
+    if (conn && ecp_conn_is_inb(conn) && (s_idx == ECP_ECDH_IDX_PERMA)) conn = NULL;
 
 #ifdef ECP_WITH_PTHREAD
     if (conn) pthread_mutex_lock(&conn->mutex);
@@ -1343,7 +1383,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, ECP
         rv = conn_shsec_get(conn, s_idx, c_idx, &shsec);
         if (rv == ECP_ERR_ECDH_IDX_LOCAL) {
             rv = ECP_OK;
-            l_idx = conn->out ? c_idx : s_idx;
+            l_idx = ecp_conn_is_outb(conn) ? c_idx : s_idx;
             key = conn_dhkey_get(conn, l_idx);
             if ((key == NULL) || !key->valid) rv = ECP_ERR_ECDH_IDX;
         }
@@ -1398,23 +1438,25 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, ECP
         ECPPktMeta pkt_meta;
         unsigned char *msg = payload+ECP_SIZE_PLD_HDR+1;
         size_t msg_size = dec_size-ECP_SIZE_PLD_HDR-1;
-        ecp_sock_handler_msg_t handler;
+        ecp_sock_msg_handler_t handler;
 
         if (key == NULL) return ECP_ERR;
         if ((mtype & ECP_MTYPE_MASK) >= ECP_MAX_MTYPE_SOCK) return ECP_ERR_MAX_MTYPE;
         if (mtype & ECP_MTYPE_FLAG_REP) return ECP_ERR;
 
-        memcpy(&pkt_meta.public, &public, sizeof(pkt_meta.public));
-        memcpy(&pkt_meta.shsec, &shsec, sizeof(pkt_meta.shsec));
+        memcpy(pkt_meta.public, public_buf, sizeof(pkt_meta.public));
         memcpy(pkt_meta.nonce, nonce_next, sizeof(pkt_meta.nonce));
+        memcpy(&pkt_meta.shsec, &shsec, sizeof(pkt_meta.shsec));
         pkt_meta.seq = seq_pkt;
         pkt_meta.s_idx = s_idx;
         pkt_meta.c_idx = c_idx;
 
-        handler = sock->handler[mtype & ECP_MTYPE_MASK];
+        handler = ecp_sock_get_msg_handler(sock, mtype & ECP_MTYPE_MASK);
         if (handler) {
-            rv = handler(sock, addr, parent, msg, msg_size, &pkt_meta, bufs, &conn);
-            if (rv) return rv;
+            ssize_t _rv;
+
+            _rv = handler(sock, addr, parent, msg, msg_size, &pkt_meta, bufs, &conn);
+            if (_rv < 0) return _rv;
         }
     }
 
@@ -1425,9 +1467,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, ECP
 
     if (is_open) {
 #ifdef ECP_WITH_RBUF
-        if (conn->rbuf.recv || (mtype == ECP_MTYPE_RBACK) || (mtype == ECP_MTYPE_RBFLUSH)) {
-            seq_check = 0;
-        }
+        if (ecp_rbuf_handle_seq(conn, mtype)) seq_check = 0;
 #endif
 
         if (seq_check) {
@@ -1500,15 +1540,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, ECP
 
 ecp_unpack_err:
     if (conn == NULL) return rv;
-
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn->mutex);
-#endif
-    conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
-#endif
-
+    ecp_conn_refcount_dec(conn);
     return rv;
 }
 
@@ -1525,18 +1557,11 @@ ssize_t ecp_pkt_handle(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent,
     if (conn) {
 #ifdef ECP_WITH_RBUF
         if (conn->rbuf.recv) {
-            rv = ecp_rbuf_recv_store(conn, seq, bufs->payload->buffer+ECP_SIZE_PLD_HDR, pld_size-ECP_SIZE_PLD_HDR, bufs);
+            rv = ecp_rbuf_store(conn, seq, bufs->payload->buffer+ECP_SIZE_PLD_HDR, pld_size-ECP_SIZE_PLD_HDR, bufs);
         }
 #endif
         if (rv == 0) rv = ecp_conn_handle_msg(conn, seq, bufs->payload->buffer+ECP_SIZE_PLD_HDR, pld_size-ECP_SIZE_PLD_HDR, bufs);
-
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
+        ecp_conn_refcount_dec(conn);
     } else {
         rv = pld_size-ECP_SIZE_PLD_HDR;
     }
@@ -1758,7 +1783,7 @@ static ssize_t pld_send(ECPConnection *conn, ECPBuffer *packet, unsigned char s_
 
 #ifdef ECP_WITH_RBUF
     if (conn->rbuf.send) {
-        return ecp_rbuf_pkt_send(conn->rbuf.send, conn->sock, &addr, packet, rv, flags, ti, si);
+        return ecp_rbuf_pkt_send(conn, conn->sock, &addr, packet, rv, flags, ti, si);
     }
 #endif
 
diff --git a/ecp/src/core.h b/ecp/src/core.h
index bf5228b..bf04947 100644
--- a/ecp/src/core.h
+++ b/ecp/src/core.h
@@ -17,6 +17,7 @@
 #define ECP_ERR_ALLOC               -3
 #define ECP_ERR_SIZE                -4
 #define ECP_ERR_ITER                -5
+#define ECP_ERR_BUSY                -6
 
 #define ECP_ERR_MAX_SOCK_CONN       -10
 #define ECP_ERR_MAX_CTYPE           -11
@@ -89,14 +90,29 @@
 #define ECP_MTYPE_DIR_REQ           (ECP_MTYPE_DIR)
 #define ECP_MTYPE_DIR_REP           (ECP_MTYPE_DIR  | ECP_MTYPE_FLAG_REP)
 
-#define ECP_CONN_FLAG_REG           0x01
-#define ECP_CONN_FLAG_OPEN          0x02
+#define ECP_CONN_FLAG_OUTB          0x01
+#define ECP_CONN_FLAG_NEW           0x02
+#define ECP_CONN_FLAG_REG           0x04
+#define ECP_CONN_FLAG_OPEN          0x08
 
 #define ECP_SEND_FLAG_REPLY         0x01
 #define ECP_SEND_FLAG_MORE          0x02
 
-#define ecp_conn_is_reg(conn)       ((conn->flags) & ECP_CONN_FLAG_REG)
-#define ecp_conn_is_open(conn)      ((conn->flags) & ECP_CONN_FLAG_OPEN)
+#define ecp_conn_is_inb(conn)     (!((conn)->flags_ro & ECP_CONN_FLAG_OUTB))
+#define ecp_conn_is_outb(conn)      ((conn)->flags_ro & ECP_CONN_FLAG_OUTB)
+#define ecp_conn_is_new(conn)       ((conn)->flags_ro & ECP_CONN_FLAG_NEW)
+#define ecp_conn_is_reg(conn)       ((conn)->flags    & ECP_CONN_FLAG_REG)
+#define ecp_conn_is_open(conn)      ((conn)->flags    & ECP_CONN_FLAG_OPEN)
+
+#define ecp_conn_set_outb(conn)     ((conn)->flags_ro |= ECP_CONN_FLAG_OUTB)
+#define ecp_conn_set_new(conn)      ((conn)->flags_ro |= ECP_CONN_FLAG_NEW)
+#define ecp_conn_set_reg(conn)      ((conn)->flags    |= ECP_CONN_FLAG_REG)
+#define ecp_conn_set_open(conn)     ((conn)->flags    |= ECP_CONN_FLAG_OPEN)
+
+#define ecp_conn_clr_outb(conn)     ((conn)->flags_ro &= ~ECP_CONN_FLAG_OUTB)
+#define ecp_conn_clr_new(conn)      ((conn)->flags_ro &= ~ECP_CONN_FLAG_NEW)
+#define ecp_conn_clr_reg(conn)      ((conn)->flags    &= ~ECP_CONN_FLAG_REG)
+#define ecp_conn_clr_open(conn)     ((conn)->flags    &= ~ECP_CONN_FLAG_OPEN)
 
 // typedef long ssize_t;
 
@@ -126,7 +142,7 @@ typedef uint32_t ecp_seq_t;
 #define ECP_SIZE_PLD(X,F)           ((X) + ECP_SIZE_PLD_HDR+1+ECP_SIZE_MT_FLAG(F))
 #define ECP_SIZE_PKT(X,F)           (ECP_SIZE_PKT_HDR+ECP_SIZE_PLD(X,F)+ECP_AEAD_SIZE_TAG)
 
-#define ECP_SIZE_MSG_BUF(T,P)       ((P) && (P)->out && (((T) == ECP_MTYPE_OPEN_REQ) || ((T) == ECP_MTYPE_KGET_REQ)) ? ECP_SIZE_PLD_HDR+3+2*ECP_ECDH_SIZE_KEY : ECP_SIZE_PLD_HDR+1)
+#define ECP_SIZE_MSG_BUF(T,P)       ((P) && ecp_conn_is_outb(P) && (((T) == ECP_MTYPE_OPEN_REQ) || ((T) == ECP_MTYPE_KGET_REQ)) ? ECP_SIZE_PLD_HDR+3+2*ECP_ECDH_SIZE_KEY : ECP_SIZE_PLD_HDR+1)
 
 #define ECP_SIZE_PLD_BUF(X,T,C)     (ECP_SIZE_PLD(X,T)+(C)->pcount*(ECP_SIZE_PKT_HDR+ECP_SIZE_MSG_BUF(T,(C)->parent)+ECP_AEAD_SIZE_TAG))
 #define ECP_SIZE_PKT_BUF(X,T,C)     (ECP_SIZE_PLD_BUF(X,T,C)+ECP_SIZE_PKT_HDR+ECP_AEAD_SIZE_TAG)
@@ -150,7 +166,6 @@ struct ECPDirList;
 #include "platform/transport.h"
 #include "crypto/crypto.h"
 #include "timer.h"
-#include "dir_srv.h"
 
 #ifdef ECP_WITH_RBUF
 #include "rbuf.h"
@@ -158,13 +173,11 @@ struct ECPDirList;
 
 typedef int (*ecp_rng_t) (void *, size_t);
 
-typedef int (*ecp_sock_handler_msg_t) (struct ECPSocket *s, ECPNetAddr *a, struct ECPConnection *p, unsigned char *msg, size_t sz, struct ECPPktMeta *m, struct ECP2Buffer *b, struct ECPConnection **c);
-typedef ssize_t (*ecp_conn_handler_msg_t) (struct ECPConnection *c, ecp_seq_t s, unsigned char t, unsigned char *msg, ssize_t sz, struct ECP2Buffer *b);
+typedef ssize_t (*ecp_sock_msg_handler_t) (struct ECPSocket *s, ECPNetAddr *a, struct ECPConnection *p, unsigned char *msg, size_t sz, struct ECPPktMeta *m, struct ECP2Buffer *b, struct ECPConnection **c);
+typedef ssize_t (*ecp_conn_msg_handler_t) (struct ECPConnection *c, ecp_seq_t s, unsigned char t, unsigned char *msg, ssize_t sz, struct ECP2Buffer *b);
 
-typedef struct ECPConnection * (*ecp_conn_alloc_t) (unsigned char t);
+typedef struct ECPConnection * (*ecp_conn_alloc_t) (struct ECPSocket *s, unsigned char t);
 typedef void (*ecp_conn_free_t) (struct ECPConnection *c);
-typedef int (*ecp_conn_create_t) (struct ECPConnection *c, unsigned char *msg, size_t sz);
-typedef void (*ecp_conn_destroy_t) (struct ECPConnection *c);
 typedef ssize_t (*ecp_conn_open_t) (struct ECPConnection *c);
 typedef void (*ecp_conn_close_t) (struct ECPConnection *c);
 
@@ -225,18 +238,15 @@ typedef struct ECPFragIter {
 
 typedef struct ECPPktMeta {
     ecp_aead_key_t shsec;
-    ecp_dh_public_t public;
     ecp_seq_t seq;
+    unsigned char public[ECP_ECDH_SIZE_KEY];
     unsigned char nonce[ECP_AEAD_SIZE_NONCE];
     unsigned char s_idx;
     unsigned char c_idx;
 } ECPPktMeta;
 
 typedef struct ECPConnHandler {
-    ecp_conn_handler_msg_t msg[ECP_MAX_MTYPE];
-    ecp_conn_create_t conn_create;
-    ecp_conn_destroy_t conn_destroy;
-    ecp_conn_open_t conn_open;
+    ecp_conn_msg_handler_t msg[ECP_MAX_MTYPE];
     ecp_conn_close_t conn_close;
 } ECPConnHandler;
 
@@ -273,7 +283,7 @@ typedef struct ECPSocket {
     unsigned char key_curr;
     ECPSockCTable conn;
     ECPTimer timer;
-    ecp_sock_handler_msg_t handler[ECP_MAX_MTYPE_SOCK];
+    ecp_sock_msg_handler_t handler[ECP_MAX_MTYPE_SOCK];
 #ifdef ECP_WITH_PTHREAD
     pthread_t rcvr_thd;
     pthread_mutex_t mutex;
@@ -282,8 +292,8 @@ typedef struct ECPSocket {
 
 typedef struct ECPConnection {
     unsigned char type;
-    unsigned char out;
     unsigned char flags;
+    unsigned char flags_ro;
     unsigned short refcount;
     ecp_seq_t seq_out;
     ecp_seq_t seq_in;
@@ -317,24 +327,34 @@ int ecp_frag_iter_init(ECPFragIter *iter, unsigned char *buffer, size_t buf_size
 void ecp_frag_iter_reset(ECPFragIter *iter);
 int ecp_dhkey_gen(ECPContext *ctx, ECPDHKey *key);
 
-int ecp_sock_create(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key);
+int ecp_sock_init(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key);
+int ecp_sock_create(ECPSocket *sock);
 void ecp_sock_destroy(ECPSocket *sock);
 int ecp_sock_open(ECPSocket *sock, void *myaddr);
 void ecp_sock_close(ECPSocket *sock);
+ecp_sock_msg_handler_t ecp_sock_get_msg_handler(ECPSocket *sock, unsigned char mtype);
 int ecp_sock_dhkey_get_curr(ECPSocket *sock, unsigned char *idx, unsigned char *public);
 int ecp_sock_dhkey_new(ECPSocket *sock);
 
-int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype);
+int ecp_conn_init(ECPConnection *conn, ECPSocket *sock, unsigned char ctype);
+int ecp_conn_create(ECPConnection *conn);
 void ecp_conn_destroy(ECPConnection *conn);
+int ecp_conn_create_inb(ECPConnection *conn, ECPConnection *parent, unsigned char c_idx, unsigned char *public);
+int ecp_conn_create_outb(ECPConnection *conn, ECPNode *node);
+int ecp_conn_insert(ECPConnection *conn);
 int ecp_conn_register(ECPConnection *conn);
-void ecp_conn_unregister(ECPConnection *conn);
+void ecp_conn_unregister(ECPConnection *conn, unsigned short *refcount);
 
-int ecp_conn_set_remote(ECPConnection *conn, ECPNode *node);
 int ecp_conn_get_dirlist(ECPConnection *conn, ECPNode *node);
 int ecp_conn_open(ECPConnection *conn, ECPNode *node);
-int ecp_conn_close(ECPConnection *conn, ecp_cts_t timeout);
+void _ecp_conn_close(ECPConnection *conn);
+int ecp_conn_close(ECPConnection *conn);
 int ecp_conn_reset(ECPConnection *conn);
+void ecp_conn_refcount_inc(ECPConnection *conn);
+void ecp_conn_refcount_dec(ECPConnection *conn);
 int ecp_conn_handler_init(ECPConnHandler *handler);
+ecp_conn_msg_handler_t ecp_conn_get_msg_handler(ECPConnection *conn, unsigned char mtype);
+ecp_conn_close_t ecp_conn_get_close_handler(ECPConnection *conn);
 
 int ecp_conn_dhkey_new(ECPConnection *conn);
 int ecp_conn_dhkey_new_pub(ECPConnection *conn, unsigned char idx, unsigned char *public);
@@ -345,13 +365,14 @@ ssize_t ecp_conn_send_kget(ECPConnection *conn);
 ssize_t ecp_conn_send_kput(ECPConnection *conn);
 ssize_t ecp_conn_send_dir(ECPConnection *conn);
 
+ssize_t _ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b, int *was_open);
 ssize_t ecp_conn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b);
+ssize_t _ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b, ecp_conn_open_t conn_open);
 ssize_t ecp_conn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b);
 ssize_t ecp_conn_handle_kput(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b);
-ssize_t ecp_conn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b);
 ssize_t ecp_conn_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs);
-int ecp_sock_handle_open(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn);
-int ecp_sock_handle_kget(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn);
+ssize_t ecp_sock_handle_open(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn);
+ssize_t ecp_sock_handle_kget(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn);
 
 ssize_t _ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, ECPPktMeta *pkt_meta, unsigned char *payload, size_t pld_size);
 ssize_t ecp_pack(ECPContext *ctx, ECPConnection *parent, ECPBuffer *packet, ECPPktMeta *pkt_meta, ECPBuffer *payload, size_t pld_size, ECPNetAddr *addr) ;
diff --git a/ecp/src/dir.c b/ecp/src/dir.c
index 8bc7a94..46d152e 100644
--- a/ecp/src/dir.c
+++ b/ecp/src/dir.c
@@ -2,6 +2,7 @@
 #include "cr.h"
 
 #include "dir.h"
+#include "dir_srv.h"
 
 static int dir_update(ECPDirList *list, ECPDirItem *item) {
     int i;
diff --git a/ecp/src/dir_srv.c b/ecp/src/dir_srv.c
index f5d1893..563326d 100644
--- a/ecp/src/dir_srv.c
+++ b/ecp/src/dir_srv.c
@@ -2,6 +2,7 @@
 #include "cr.h"
 
 #include "dir.h"
+#include "dir_srv.h"
 
 #ifdef ECP_WITH_DIRSRV
 
@@ -21,28 +22,29 @@ ssize_t ecp_dir_handle_update(ECPConnection *conn, ecp_seq_t seq, unsigned char
     } else {
         return ECP_ERR;
     }
-
 }
 
-int ecp_dir_handle_req(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
+ssize_t ecp_dir_handle_req(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *parent, unsigned char *msg, size_t msg_size, ECPPktMeta *pkt_meta, ECP2Buffer *bufs, ECPConnection **_conn) {
     ECPContext *ctx = sock->ctx;
     ECPBuffer *packet = bufs->packet;
     ECPBuffer *payload = bufs->payload;
     ECPDirList *dir_online = ctx->dir_online;
-    ssize_t _rv;
-    int rv;
+    ssize_t rv;
+    int _rv;
+
+    if (msg_size < 0) return msg_size;
 
     ecp_pld_set_type(payload->buffer, payload->size, ECP_MTYPE_DIR_REP);
     msg = ecp_pld_get_buf(payload->buffer, payload->size);
     msg_size = payload->size - (msg - payload->buffer);
 
-    rv = ecp_dir_serialize(dir_online, msg, msg_size);
-    if (rv) return rv;
+    _rv = ecp_dir_serialize(dir_online, msg, msg_size);
+    if (_rv) return _rv;
 
-    _rv = ecp_pld_send_tr(sock, addr, parent, packet, pkt_meta, payload, ECP_SIZE_PLD(dir_online->count * ECP_SIZE_DIR_ITEM, ECP_MTYPE_DIR_REP), 0);
-    if (_rv < 0) return _rv;
+    rv = ecp_pld_send_tr(sock, addr, parent, packet, pkt_meta, payload, ECP_SIZE_PLD(dir_online->count * ECP_SIZE_DIR_ITEM, ECP_MTYPE_DIR_REP), 0);
+    if (rv < 0) return rv;
 
-    return ECP_OK;
+    return msg_size;
 }
 
 #endif  /* ECP_WITH_DIRSRV */
\ No newline at end of file
diff --git a/ecp/src/dir_srv.h b/ecp/src/dir_srv.h
index cc2ebbe..3fc14ee 100644
--- a/ecp/src/dir_srv.h
+++ b/ecp/src/dir_srv.h
@@ -2,6 +2,6 @@
 
 int ecp_dir_init(struct ECPContext *ctx, struct ECPDirList *dir_online, struct ECPDirList *dir_shadow);
 ssize_t ecp_dir_handle_update(struct ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, struct ECP2Buffer *b);
-int ecp_dir_handle_req(struct ECPSocket *sock, struct ECPNetAddr *addr, struct ECPConnection *parent, unsigned char *msg, size_t msg_size, struct ECPPktMeta *pkt_meta, struct ECP2Buffer *bufs, struct ECPConnection **_conn);
+ssize_t ecp_dir_handle_req(struct ECPSocket *sock, struct ECPNetAddr *addr, struct ECPConnection *parent, unsigned char *msg, size_t msg_size, struct ECPPktMeta *pkt_meta, struct ECP2Buffer *bufs, struct ECPConnection **_conn);
 
 #endif  /* ECP_WITH_DIRSRV */
\ No newline at end of file
diff --git a/ecp/src/fe310/transport.h b/ecp/src/fe310/transport.h
index 0fcf43b..47ad482 100644
--- a/ecp/src/fe310/transport.h
+++ b/ecp/src/fe310/transport.h
@@ -1,5 +1,7 @@
 #include <eos/sock.h>
 
+#define ECP_IPv4_ADDR_SIZE          4
+
 typedef EOSNetAddr ECPNetAddr;
 typedef int ECPNetSock;
 
diff --git a/ecp/src/rbuf.c b/ecp/src/rbuf.c
index 9a5bd8c..9680d14 100644
--- a/ecp/src/rbuf.c
+++ b/ecp/src/rbuf.c
@@ -1,6 +1,6 @@
 #include "core.h"
 
-int ecp_rbuf_init(ECPRBuffer *rbuf, ECPRBMessage *msg, unsigned int msg_size) {
+int _ecp_rbuf_init(ECPRBuffer *rbuf, ECPRBMessage *msg, unsigned int msg_size) {
     rbuf->msg = msg;
     if (msg_size) {
         if (msg == NULL) return ECP_ERR;
@@ -13,6 +13,35 @@ int ecp_rbuf_init(ECPRBuffer *rbuf, ECPRBMessage *msg, unsigned int msg_size) {
     return ECP_OK;
 }
 
+int _ecp_rbuf_start(ECPRBuffer *rbuf, ecp_seq_t seq) {
+    rbuf->seq_max = seq;
+    rbuf->seq_start = seq + 1;
+
+    return ECP_OK;
+}
+
+int _ecp_rbuf_msg_idx(ECPRBuffer *rbuf, ecp_seq_t seq) {
+    ecp_seq_t seq_offset = seq - rbuf->seq_start;
+
+    // This also checks for seq_start <= seq if seq type range >> rbuf->msg_size
+    if (seq_offset < rbuf->msg_size) return ECP_RBUF_IDX_MASK(rbuf->msg_start + seq_offset, rbuf->msg_size);
+    return ECP_ERR_RBUF_FULL;
+}
+
+ssize_t _ecp_rbuf_msg_store(ECPRBuffer *rbuf, ecp_seq_t seq, int idx, unsigned char *msg, size_t msg_size, unsigned char test_flags, unsigned char set_flags) {
+    idx = idx < 0 ? _ecp_rbuf_msg_idx(rbuf, seq) : idx;
+    if (idx < 0) return idx;
+
+    if (rbuf->msg == NULL) return 0;
+    if (test_flags && (test_flags & rbuf->msg[idx].flags)) return ECP_ERR_RBUF_DUP;
+
+    if (msg_size) memcpy(rbuf->msg[idx].msg, msg, msg_size);
+    rbuf->msg[idx].size = msg_size;
+    rbuf->msg[idx].flags = set_flags;
+
+    return msg_size;
+}
+
 int ecp_rbuf_create(ECPConnection *conn, ECPRBSend *buf_s, ECPRBMessage *msg_s, unsigned int msg_s_size, ECPRBRecv *buf_r, ECPRBMessage *msg_r, unsigned int msg_r_size) {
     int rv;
 
@@ -43,35 +72,6 @@ void ecp_rbuf_destroy(ECPConnection *conn) {
     ecp_rbuf_recv_destroy(conn);
 }
 
-int ecp_rbuf_start(ECPRBuffer *rbuf, ecp_seq_t seq) {
-    rbuf->seq_max = seq;
-    rbuf->seq_start = seq + 1;
-
-    return ECP_OK;
-}
-
-int ecp_rbuf_msg_idx(ECPRBuffer *rbuf, ecp_seq_t seq) {
-    ecp_seq_t seq_offset = seq - rbuf->seq_start;
-
-    // This also checks for seq_start <= seq if seq type range >> rbuf->msg_size
-    if (seq_offset < rbuf->msg_size) return ECP_RBUF_IDX_MASK(rbuf->msg_start + seq_offset, rbuf->msg_size);
-    return ECP_ERR_RBUF_FULL;
-}
-
-ssize_t ecp_rbuf_msg_store(ECPRBuffer *rbuf, ecp_seq_t seq, int idx, unsigned char *msg, size_t msg_size, unsigned char test_flags, unsigned char set_flags) {
-    idx = idx < 0 ? ecp_rbuf_msg_idx(rbuf, seq) : idx;
-    if (idx < 0) return idx;
-
-    if (rbuf->msg == NULL) return 0;
-    if (test_flags && (test_flags & rbuf->msg[idx].flags)) return ECP_ERR_RBUF_DUP;
-
-    if (msg_size) memcpy(rbuf->msg[idx].msg, msg, msg_size);
-    rbuf->msg[idx].size = msg_size;
-    rbuf->msg[idx].flags = set_flags;
-
-    return msg_size;
-}
-
 ssize_t ecp_rbuf_pld_send(ECPConnection *conn, ECPBuffer *packet, ECPBuffer *payload, size_t pld_size, unsigned char flags, ecp_seq_t seq) {
     ECPSocket *sock = conn->sock;
     ECPContext *ctx = sock->ctx;
@@ -96,3 +96,107 @@ ssize_t ecp_rbuf_pld_send(ECPConnection *conn, ECPBuffer *packet, ECPBuffer *pay
     return rv;
 }
 
+int ecp_rbuf_handle_seq(ECPConnection *conn, unsigned char mtype) {
+    if (conn->rbuf.recv || (mtype == ECP_MTYPE_RBACK) || (mtype == ECP_MTYPE_RBFLUSH)) return 1;
+    return 0;
+}
+
+int ecp_rbuf_set_seq(ECPConnection *conn, ECPSeqItem *si, unsigned char *payload, size_t pld_size) {
+    ECPRBSend *buf;
+    unsigned char mtype;
+    int idx;
+    int rv;
+
+    if (si->rb_pass) return ECP_OK;
+
+    buf = conn->rbuf.send;
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_lock(&buf->mutex);
+#endif
+    idx = _ecp_rbuf_msg_idx(&buf->rbuf, si->seq);
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_unlock(&buf->mutex);
+#endif
+
+    if (idx < 0) return idx;
+
+    rv = ecp_pld_get_type(payload, pld_size, &mtype);
+    if (rv) return rv;
+
+    si->rb_mtype = mtype;
+    si->rb_idx = idx;
+    buf->rbuf.msg[idx].size = 0;
+    buf->rbuf.msg[idx].flags = 0;
+
+    return ECP_OK;
+}
+
+ssize_t ecp_rbuf_pkt_send(ECPConnection *conn, ECPSocket *sock, ECPNetAddr *addr, ECPBuffer *packet, size_t pkt_size, unsigned char flags, ECPTimerItem *ti, ECPSeqItem *si) {
+    ECPRBSend *buf;
+    int do_send = 1;
+    ssize_t rv = 0;
+
+    buf = conn->rbuf.send;
+    if (!si->rb_pass) {
+        unsigned char flags = 0;
+        ecp_seq_t seq = si->seq;
+        unsigned int idx = si->rb_idx;
+        unsigned char mtype = si->rb_mtype & ECP_MTYPE_MASK;
+
+        if (mtype < ECP_MAX_MTYPE_SYS) flags |= ECP_RBUF_FLAG_SYS;
+
+        rv = _ecp_rbuf_msg_store(&buf->rbuf, seq, idx, packet->buffer, pkt_size, 0, flags);
+        if (rv < 0) return rv;
+
+        if (buf->flags & ECP_RBUF_FLAG_CCONTROL) {
+            int _rv = ECP_OK;
+
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_lock(&buf->mutex);
+#endif
+
+            if (ECP_SEQ_LT(buf->rbuf.seq_max, seq)) buf->rbuf.seq_max = seq;
+
+            if (buf->cnt_cc || (buf->in_transit >= buf->win_size)) {
+                if (!buf->cnt_cc) buf->seq_cc = seq;
+                buf->cnt_cc++;
+                buf->rbuf.msg[idx].flags |= ECP_RBUF_FLAG_IN_CCONTROL;
+                do_send = 0;
+                if (ti) {
+                    ECPRBTimer *timer = &buf->timer;
+                    ECPRBTimerItem *item = &timer->item[timer->idx_w];
+
+                    if (!item->occupied) {
+                        item->occupied = 1;
+                        item->item = *ti;
+                        buf->rbuf.msg[idx].idx_t = timer->idx_w;
+                        timer->idx_w = (timer->idx_w) % ECP_MAX_TIMER;
+                    } else {
+                        _rv = ECP_ERR_MAX_TIMER;
+                    }
+                } else {
+                    buf->rbuf.msg[idx].idx_t = -1;
+                }
+            } else {
+                buf->in_transit++;
+            }
+
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_unlock(&buf->mutex);
+#endif
+
+            if (_rv) return _rv;
+        }
+    }
+
+    if (do_send) {
+        if (ti) {
+            int _rv;
+
+            _rv = ecp_timer_push(ti);
+            if (_rv) return _rv;
+        }
+        rv = ecp_pkt_send(sock, addr, packet, pkt_size, flags);
+    }
+    return rv;
+}
diff --git a/ecp/src/rbuf.h b/ecp/src/rbuf.h
index 3a2a51b..891f29d 100644
--- a/ecp/src/rbuf.h
+++ b/ecp/src/rbuf.h
@@ -89,31 +89,32 @@ typedef struct ECPConnRBuffer {
     ECPRBSend *send;
 } ECPConnRBuffer;
 
-int ecp_rbuf_init(ECPRBuffer *rbuf, ECPRBMessage *msg, unsigned int msg_size);
+int _ecp_rbuf_init(ECPRBuffer *rbuf, ECPRBMessage *msg, unsigned int msg_size);
+int _ecp_rbuf_start(ECPRBuffer *rbuf, ecp_seq_t seq);
+int _ecp_rbuf_msg_idx(ECPRBuffer *rbuf, ecp_seq_t seq);
+ssize_t _ecp_rbuf_msg_store(ECPRBuffer *rbuf, ecp_seq_t seq, int idx, unsigned char *msg, size_t msg_size, unsigned char test_flags, unsigned char set_flags);
+
 int ecp_rbuf_create(struct ECPConnection *conn, ECPRBSend *buf_s, ECPRBMessage *msg_s, unsigned int msg_s_size, ECPRBRecv *buf_r, ECPRBMessage *msg_r, unsigned int msg_r_size);
 void ecp_rbuf_destroy(struct ECPConnection *conn);
-int ecp_rbuf_start(ECPRBuffer *rbuf, ecp_seq_t seq);
-int ecp_rbuf_msg_idx(ECPRBuffer *rbuf, ecp_seq_t seq);
-
-ssize_t ecp_rbuf_msg_store(ECPRBuffer *rbuf, ecp_seq_t seq, int idx, unsigned char *msg, size_t msg_size, unsigned char test_flags, unsigned char set_flags);
 ssize_t ecp_rbuf_pld_send(struct ECPConnection *conn, struct ECPBuffer *packet, struct ECPBuffer *payload, size_t pld_size, unsigned char flags, ecp_seq_t seq);
+int ecp_rbuf_handle_seq(struct ECPConnection *conn, unsigned char mtype);
+int ecp_rbuf_set_seq(struct ECPConnection *conn, struct ECPSeqItem *si, unsigned char *payload, size_t pld_size);
+ssize_t ecp_rbuf_pkt_send(struct ECPConnection *conn, struct ECPSocket *sock, ECPNetAddr *addr, struct ECPBuffer *packet, size_t pkt_size, unsigned char flags, ECPTimerItem *ti, struct ECPSeqItem *si);
 
 int ecp_rbuf_recv_create(struct ECPConnection *conn, ECPRBRecv *buf, ECPRBMessage *msg, unsigned int msg_size);
 void ecp_rbuf_recv_destroy(struct ECPConnection *conn);
 int ecp_rbuf_recv_start(struct ECPConnection *conn, ecp_seq_t seq);
-int ecp_rbuf_recv_set_hole(struct ECPConnection *conn, unsigned short hole_max);
-int ecp_rbuf_recv_set_delay(struct ECPConnection *conn, ecp_pts_t delay);
+int ecp_rbuf_set_hole(struct ECPConnection *conn, unsigned short hole_max);
+int ecp_rbuf_set_delay(struct ECPConnection *conn, ecp_pts_t delay);
 
-ssize_t ecp_rbuf_recv_store(struct ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, struct ECP2Buffer *b);
+ssize_t ecp_rbuf_store(struct ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, struct ECP2Buffer *b);
+struct ECPFragIter *ecp_rbuf_get_frag_iter(struct ECPConnection *conn);
 
 int ecp_rbuf_send_create(struct ECPConnection *conn, ECPRBSend *buf, ECPRBMessage *msg, unsigned int msg_size);
 void ecp_rbuf_send_destroy(struct ECPConnection *conn);
 int ecp_rbuf_send_start(struct ECPConnection *conn);
-int ecp_rbuf_send_flush(struct ECPConnection *conn);
-int ecp_rbuf_send_set_wsize(struct ECPConnection *conn, ecp_win_t size);
-
-int ecp_rbuf_pkt_prep(ECPRBSend *buf, struct ECPSeqItem *si, unsigned char mtype);
-ssize_t ecp_rbuf_pkt_send(ECPRBSend *buf, struct ECPSocket *sock, ECPNetAddr *addr, struct ECPBuffer *packet, size_t pkt_size, unsigned char flags, ECPTimerItem *ti, struct ECPSeqItem *si);
+int ecp_rbuf_flush(struct ECPConnection *conn);
+int ecp_rbuf_set_wsize(struct ECPConnection *conn, ecp_win_t size);
 
 ssize_t ecp_rbuf_handle_ack(struct ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, struct ECP2Buffer *b);
 ssize_t ecp_rbuf_handle_flush(struct ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, struct ECP2Buffer *b);
diff --git a/ecp/src/rbuf_recv.c b/ecp/src/rbuf_recv.c
index 17bbd01..f2bb1c2 100644
--- a/ecp/src/rbuf_recv.c
+++ b/ecp/src/rbuf_recv.c
@@ -18,8 +18,8 @@ static ssize_t msg_store(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg,
     mtype &= ECP_MTYPE_MASK;
     if (mtype < ECP_MAX_MTYPE_SYS) flags |= ECP_RBUF_FLAG_SYS;
 
-    if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
 #ifdef ECP_WITH_MSGQ
+    if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
         ecp_seq_t seq_offset;
         int _rv = ECP_OK;
 
@@ -29,10 +29,10 @@ static ssize_t msg_store(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg,
         pthread_mutex_unlock(&buf->msgq.mutex);
 
         if (_rv) return _rv;
-#endif
     }
+#endif
 
-    rv = ecp_rbuf_msg_store(&buf->rbuf, seq, -1, msg, msg_size, ECP_RBUF_FLAG_IN_RBUF | ECP_RBUF_FLAG_IN_MSGQ, flags);
+    rv = _ecp_rbuf_msg_store(&buf->rbuf, seq, -1, msg, msg_size, ECP_RBUF_FLAG_IN_RBUF | ECP_RBUF_FLAG_IN_MSGQ, flags);
     if (rv < 0) return rv;
 
     if (ECP_SEQ_LT(buf->rbuf.seq_max, seq)) buf->rbuf.seq_max = seq;
@@ -102,8 +102,8 @@ static void msg_flush(ECPConnection *conn, ECP2Buffer *b) {
                 }
 
                 seq_next = seq + 1;
-                if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
 #ifdef ECP_WITH_MSGQ
+                if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
                     unsigned char mtype;
 
                     rv = ecp_msg_get_type(buf->rbuf.msg[idx].msg, buf->rbuf.msg[idx].size, &mtype);
@@ -111,10 +111,10 @@ static void msg_flush(ECPConnection *conn, ECP2Buffer *b) {
                     if (rv) break;
 
                     buf->rbuf.msg[idx].flags |= ECP_RBUF_FLAG_IN_MSGQ;
+                } else
+
 #endif
-                } else {
                     ecp_conn_handle_msg(conn, seq, buf->rbuf.msg[idx].msg, buf->rbuf.msg[idx].size, b);
-                }
             }
             buf->rbuf.msg[idx].flags &= ~ECP_RBUF_FLAG_IN_RBUF;
         } else {
@@ -232,7 +232,7 @@ int ecp_rbuf_recv_create(ECPConnection *conn, ECPRBRecv *buf, ECPRBMessage *msg,
     int rv;
 
     memset(buf, 0, sizeof(ECPRBRecv));
-    rv = ecp_rbuf_init(&buf->rbuf, msg, msg_size);
+    rv = _ecp_rbuf_init(&buf->rbuf, msg, msg_size);
     if (rv) return rv;
 
     buf->ack_map = ECP_ACK_FULL;
@@ -266,20 +266,20 @@ int ecp_rbuf_recv_start(ECPConnection *conn, ecp_seq_t seq) {
 
     seq--;
     buf->seq_ack = seq;
-    rv = ecp_rbuf_start(&buf->rbuf, seq);
+    rv = _ecp_rbuf_start(&buf->rbuf, seq);
     if (rv) return rv;
 
-    if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
 #ifdef ECP_WITH_MSGQ
+    if (buf->flags & ECP_RBUF_FLAG_MSGQ) {
         rv = ecp_conn_msgq_start(&buf->msgq, seq);
         if (rv) return rv;
-#endif
     }
+#endif
 
     return ECP_OK;
 }
 
-int ecp_rbuf_recv_set_hole(ECPConnection *conn, unsigned short hole_max) {
+int ecp_rbuf_set_hole(ECPConnection *conn, unsigned short hole_max) {
     ECPRBRecv *buf = conn->rbuf.recv;
 
     buf->hole_max = hole_max;
@@ -289,7 +289,7 @@ int ecp_rbuf_recv_set_hole(ECPConnection *conn, unsigned short hole_max) {
     return ECP_OK;
 }
 
-int ecp_rbuf_recv_set_delay(ECPConnection *conn, ecp_pts_t delay) {
+int ecp_rbuf_set_delay(ECPConnection *conn, ecp_pts_t delay) {
     ECPRBRecv *buf = conn->rbuf.recv;
 
     buf->deliver_delay = delay;
@@ -297,7 +297,7 @@ int ecp_rbuf_recv_set_delay(ECPConnection *conn, ecp_pts_t delay) {
     return ECP_OK;
 }
 
-ssize_t ecp_rbuf_recv_store(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, ECP2Buffer *b) {
+ssize_t ecp_rbuf_store(ECPConnection *conn, ecp_seq_t seq, unsigned char *msg, size_t msg_size, ECP2Buffer *b) {
     ECPRBRecv *buf = conn->rbuf.recv;
     ecp_seq_t ack_pkt = 0;
     ssize_t rv;
@@ -361,3 +361,8 @@ ssize_t ecp_rbuf_recv_store(ECPConnection *conn, ecp_seq_t seq, unsigned char *m
     return rv;
 }
 
+
+ECPFragIter *ecp_rbuf_get_frag_iter(ECPConnection *conn) {
+    if (conn->rbuf.recv) return conn->rbuf.recv->frag_iter;
+    return NULL;
+}
diff --git a/ecp/src/rbuf_send.c b/ecp/src/rbuf_send.c
index a680285..faf2a7d 100644
--- a/ecp/src/rbuf_send.c
+++ b/ecp/src/rbuf_send.c
@@ -41,7 +41,7 @@ static void cc_flush(ECPConnection *conn) {
     unsigned short max_t = 0;
 
     if (pkt_to_send) {
-        unsigned int idx = ecp_rbuf_msg_idx(rbuf, buf->seq_cc);
+        unsigned int idx = _ecp_rbuf_msg_idx(rbuf, buf->seq_cc);
         unsigned int _idx = idx;
 
         for (i=0; i<pkt_to_send; i++) {
@@ -118,7 +118,7 @@ ssize_t ecp_rbuf_handle_ack(ECPConnection *conn, ecp_seq_t seq, unsigned char mt
 #endif
 
     ECPRBuffer *rbuf = &buf->rbuf;
-    int idx = ecp_rbuf_msg_idx(rbuf, seq_ack);
+    int idx = _ecp_rbuf_msg_idx(rbuf, seq_ack);
     if (idx < 0) rv = idx;
 
     if (!rv) {
@@ -217,7 +217,7 @@ int ecp_rbuf_send_create(ECPConnection *conn, ECPRBSend *buf, ECPRBMessage *msg,
     int rv;
 
     memset(buf, 0, sizeof(ECPRBRecv));
-    rv = ecp_rbuf_init(&buf->rbuf, msg, msg_size);
+    rv = _ecp_rbuf_init(&buf->rbuf, msg, msg_size);
     if (rv) return rv;
 
 #ifdef ECP_WITH_PTHREAD
@@ -246,10 +246,10 @@ int ecp_rbuf_send_start(ECPConnection *conn) {
 
     if (buf == NULL) return ECP_ERR;
 
-    return ecp_rbuf_start(&buf->rbuf, conn->seq_out);
+    return _ecp_rbuf_start(&buf->rbuf, conn->seq_out);
 }
 
-int ecp_rbuf_send_set_wsize(ECPConnection *conn, ecp_win_t size) {
+int ecp_rbuf_set_wsize(ECPConnection *conn, ecp_win_t size) {
     ECPRBSend *buf = conn->rbuf.send;
 
     if (buf == NULL) return ECP_ERR;
@@ -268,7 +268,7 @@ int ecp_rbuf_send_set_wsize(ECPConnection *conn, ecp_win_t size) {
     return ECP_OK;
 }
 
-int ecp_rbuf_send_flush(ECPConnection *conn) {
+int ecp_rbuf_flush(ECPConnection *conn) {
     ECPRBSend *buf = conn->rbuf.send;
     ecp_seq_t seq;
     ssize_t rv;
@@ -303,94 +303,3 @@ int ecp_rbuf_send_flush(ECPConnection *conn) {
 
     return ECP_OK;
 }
-
-int ecp_rbuf_pkt_prep(ECPRBSend *buf, ECPSeqItem *si, unsigned char mtype) {
-    int idx;
-
-    if (si->rb_pass) return ECP_OK;
-
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&buf->mutex);
-#endif
-    idx = ecp_rbuf_msg_idx(&buf->rbuf, si->seq);
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&buf->mutex);
-#endif
-
-    if (idx < 0) return idx;
-
-    si->rb_mtype = mtype;
-    si->rb_idx = idx;
-    buf->rbuf.msg[idx].size = 0;
-    buf->rbuf.msg[idx].flags = 0;
-
-    return ECP_OK;
-}
-
-ssize_t ecp_rbuf_pkt_send(ECPRBSend *buf, ECPSocket *sock, ECPNetAddr *addr, ECPBuffer *packet, size_t pkt_size, unsigned char flags, ECPTimerItem *ti, ECPSeqItem *si) {
-    int do_send = 1;
-    ssize_t rv = 0;
-
-    if (!si->rb_pass) {
-        unsigned char flags = 0;
-        ecp_seq_t seq = si->seq;
-        unsigned int idx = si->rb_idx;
-        unsigned char mtype = si->rb_mtype & ECP_MTYPE_MASK;
-
-        if (mtype < ECP_MAX_MTYPE_SYS) flags |= ECP_RBUF_FLAG_SYS;
-
-        rv = ecp_rbuf_msg_store(&buf->rbuf, seq, idx, packet->buffer, pkt_size, 0, flags);
-        if (rv < 0) return rv;
-
-        if (buf->flags & ECP_RBUF_FLAG_CCONTROL) {
-            int _rv = ECP_OK;
-
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&buf->mutex);
-#endif
-
-            if (ECP_SEQ_LT(buf->rbuf.seq_max, seq)) buf->rbuf.seq_max = seq;
-
-            if (buf->cnt_cc || (buf->in_transit >= buf->win_size)) {
-                if (!buf->cnt_cc) buf->seq_cc = seq;
-                buf->cnt_cc++;
-                buf->rbuf.msg[idx].flags |= ECP_RBUF_FLAG_IN_CCONTROL;
-                do_send = 0;
-                if (ti) {
-                    ECPRBTimer *timer = &buf->timer;
-                    ECPRBTimerItem *item = &timer->item[timer->idx_w];
-
-                    if (!item->occupied) {
-                        item->occupied = 1;
-                        item->item = *ti;
-                        buf->rbuf.msg[idx].idx_t = timer->idx_w;
-                        timer->idx_w = (timer->idx_w) % ECP_MAX_TIMER;
-                    } else {
-                        _rv = ECP_ERR_MAX_TIMER;
-                    }
-                } else {
-                    buf->rbuf.msg[idx].idx_t = -1;
-                }
-            } else {
-                buf->in_transit++;
-            }
-
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&buf->mutex);
-#endif
-
-            if (_rv) return _rv;
-        }
-    }
-
-    if (do_send) {
-        if (ti) {
-            int _rv;
-
-            _rv = ecp_timer_push(ti);
-            if (_rv) return _rv;
-        }
-        rv = ecp_pkt_send(sock, addr, packet, pkt_size, flags);
-    }
-    return rv;
-}
diff --git a/ecp/src/timer.c b/ecp/src/timer.c
index 7dd3c50..28d4cb1 100644
--- a/ecp/src/timer.c
+++ b/ecp/src/timer.c
@@ -97,13 +97,7 @@ void ecp_timer_pop(ECPConnection *conn, unsigned char mtype) {
             } else {
                 memset(timer->item+i, 0, sizeof(ECPTimerItem));
             }
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&conn->mutex);
-#endif
-            conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&conn->mutex);
-#endif
+            ecp_conn_refcount_dec(conn);
             timer->head--;
             break;
         }
@@ -132,13 +126,7 @@ void ecp_timer_remove(ECPConnection *conn) {
             } else {
                 memset(timer->item+i, 0, sizeof(ECPTimerItem));
             }
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&conn->mutex);
-#endif
-            conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&conn->mutex);
-#endif
+            ecp_conn_refcount_dec(conn);
             timer->head--;
         }
     }
@@ -184,7 +172,7 @@ ecp_cts_t ecp_timer_exe(ECPSocket *sock) {
         ECPConnection *conn = to_exec[i].conn;
         unsigned char mtype = to_exec[i].mtype;
         ecp_timer_retry_t retry = to_exec[i].retry;
-        ecp_conn_handler_msg_t handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[mtype & ECP_MTYPE_MASK] : NULL;
+        ecp_conn_msg_handler_t handler = ecp_conn_get_msg_handler(conn, mtype & ECP_MTYPE_MASK);
         int rv = ECP_OK;
 
         if (to_exec[i].cnt > 0) {
@@ -199,15 +187,7 @@ ecp_cts_t ecp_timer_exe(ECPSocket *sock) {
         } else if (handler) {
             handler(conn, 0, mtype, NULL, ECP_ERR_TIMEOUT, NULL);
         }
-
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
-
+        ecp_conn_refcount_dec(conn);
     }
 
     return ret;
diff --git a/ecp/src/vconn/vconn.c b/ecp/src/vconn/vconn.c
index c414454..d60f5f2 100644
--- a/ecp/src/vconn/vconn.c
+++ b/ecp/src/vconn/vconn.c
@@ -16,51 +16,33 @@ static pthread_mutex_t key_next_mutex;
 #endif
 #endif
 
-static unsigned char key_null[ECP_ECDH_SIZE_KEY] = { 0 };
-
 static ECPConnHandler handler_vc;
 static ECPConnHandler handler_vl;
 
 #ifdef ECP_WITH_HTABLE
 
-static int vconn_create(ECPConnection *conn, unsigned char *payload, size_t size) {
-    ECPVConnIn *conn_v = (ECPVConnIn *)conn;
-    int rv;
-
-    if (conn->out) return ECP_ERR;
-    if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR;
-    if (size < 2*ECP_ECDH_SIZE_KEY) return ECP_ERR;
-
-    conn_v->key_next_curr = 0;
-    memset(conn_v->key_next, 0, sizeof(conn_v->key_next));
-    memset(conn_v->key_out, 0, sizeof(conn_v->key_out));
-    memcpy(conn_v->key_next[conn_v->key_next_curr], payload, ECP_ECDH_SIZE_KEY);
-    memcpy(conn_v->key_out, payload+ECP_ECDH_SIZE_KEY, ECP_ECDH_SIZE_KEY);
-
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&key_next_mutex);
-#endif
-    rv = ecp_ht_insert(key_next_table, conn_v->key_next[conn_v->key_next_curr], conn);
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&key_next_mutex);
-#endif
+static int key_is_null(unsigned char *key) {
+    int i;
 
-    return rv;
+    for (i=0; i<ECP_ECDH_SIZE_KEY; i++) {
+        if (key[i] != 0) return 0;
+    }
+    return 1;
 }
 
-static void vconn_destroy(ECPConnection *conn) {
+static void vconn_remove(ECPConnection *conn) {
     ECPVConnIn *conn_v = (ECPVConnIn *)conn;
+    int i;
 
-    if (conn->out) return;
     if (conn->type != ECP_CTYPE_VCONN) return;
+    if (ecp_conn_is_outb(conn)) return;
 
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&key_next_mutex);
     pthread_mutex_lock(&conn->mutex);
 #endif
-    int i;
     for (i=0; i<ECP_MAX_NODE_KEY; i++) {
-        if (memcmp(conn_v->key_next[i], key_null, ECP_ECDH_SIZE_KEY)) ecp_ht_remove(key_next_table, conn_v->key_next[i]);
+        if (!key_is_null(conn_v->key_next[i])) ecp_ht_remove(key_next_table, conn_v->key_next[i]);
     }
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&conn->mutex);
@@ -85,12 +67,16 @@ static ssize_t _vconn_send_open(ECPConnection *conn, ECPTimerItem *ti) {
     return _ecp_pld_send(conn, &packet, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, NULL, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_KGET_REQ), 0, ti);
 }
 
-static ssize_t vconn_open(ECPConnection *conn) {
+static ssize_t vconn_send_open(ECPConnection *conn) {
     ECPTimerItem ti;
-    ECPVConnection *conn_v = (ECPVConnection *)conn;
-    ECPConnection *conn_next = conn_v->next;
+    ECPVConnOut *conn_v = (ECPVConnOut *)conn;
+    ECPConnection *conn_next;
     ssize_t rv;
 
+    if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR;
+    if (ecp_conn_is_inb(conn)) return ECP_ERR;
+
+    conn_next = conn_v->next;
     if (conn_next == NULL) return ECP_ERR;
 
     rv = ecp_timer_send(conn_next, _vconn_send_open, ECP_MTYPE_KGET_REP, 3, 1000);
@@ -99,74 +85,106 @@ static ssize_t vconn_open(ECPConnection *conn) {
     return rv;
 }
 
+static ssize_t vconn_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    return _ecp_conn_handle_kget(conn, seq, mtype, msg, size, b, vconn_send_open);
+}
+
 static ssize_t vconn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    ssize_t rv;
+    int _rv;
+
     if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR;
 
     if (mtype & ECP_MTYPE_FLAG_REP) {
-        if (!conn->out) return ECP_ERR;
+        if (ecp_conn_is_inb(conn)) return ECP_ERR;
         if (size < 0) {
-            ecp_conn_handler_msg_t handler = NULL;
-            while (conn->type == ECP_CTYPE_VCONN) {
-                ECPVConnection *conn_v = (ECPVConnection *)conn;
+            ecp_conn_msg_handler_t handler;
+            while (conn && (conn->type == ECP_CTYPE_VCONN)) {
+                ECPVConnOut *conn_v = (ECPVConnOut *)conn;
                 conn = conn_v->next;
             }
-            handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[ECP_MTYPE_OPEN] : NULL;
+            if (conn) handler = ecp_conn_get_msg_handler(conn, ECP_MTYPE_OPEN);
             return handler ? handler(conn, seq, mtype, msg, size, b) : size;
         }
 
-        return ecp_conn_handle_open(conn, seq, mtype, msg, size, b);
+        rv = ecp_conn_handle_open(conn, seq, mtype, msg, size, b);
     } else {
-        int rv = ECP_OK;
 
 #ifdef ECP_WITH_HTABLE
+
         ECPVConnIn *conn_v = (ECPVConnIn *)conn;
-        unsigned char ctype = 0;
+        unsigned char ctype;
+        int is_new, do_ins;
 
-        if (conn->out) return ECP_ERR;
+        if (ecp_conn_is_outb(conn)) return ECP_ERR;
         if (size < 0) return size;
         if (size < 1+2*ECP_ECDH_SIZE_KEY) return ECP_ERR;
 
+        ctype = msg[0];
+        msg++;
+
+        is_new = ecp_conn_is_new(conn);
+        do_ins = 0;
+        if (is_new) {
+            conn_v->key_next_curr = 0;
+            memset(conn_v->key_next, 0, sizeof(conn_v->key_next));
+            memset(conn_v->key_out, 0, sizeof(conn_v->key_out));
+            memcpy(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY);
+            memcpy(conn_v->key_out, msg+ECP_ECDH_SIZE_KEY, ECP_ECDH_SIZE_KEY);
+            do_ins = 1;
+
+            _rv = ecp_conn_insert(conn);
+            if (_rv) return rv;
+        }
+
 #ifdef ECP_WITH_PTHREAD
         pthread_mutex_lock(&key_next_mutex);
         pthread_mutex_lock(&conn->mutex);
 #endif
 
-        ctype = msg[0];
-        msg++;
-
-        if (!ecp_conn_is_open(conn)) conn->flags |= ECP_CONN_FLAG_OPEN;
-        if (memcmp(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY)) {
+        _rv = ECP_OK;
+        if (!is_new && memcmp(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY)) {
             conn_v->key_next_curr = (conn_v->key_next_curr + 1) % ECP_MAX_NODE_KEY;
-            if (memcmp(conn_v->key_next[conn_v->key_next_curr], key_null, ECP_ECDH_SIZE_KEY)) ecp_ht_remove(key_next_table, conn_v->key_next[conn_v->key_next_curr]);
-            rv = ecp_ht_insert(key_next_table, conn_v->key_next[conn_v->key_next_curr], conn);
-            if (!rv) memcpy(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY);
+            if (!key_is_null(conn_v->key_next[conn_v->key_next_curr])) ecp_ht_remove(key_next_table, conn_v->key_next[conn_v->key_next_curr]);
+            memcpy(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY);
+            do_ins = 1;
         }
+        if (do_ins) _rv = ecp_ht_insert(key_next_table, conn_v->key_next[conn_v->key_next_curr], conn);
+        if (!_rv && !ecp_conn_is_open(conn)) ecp_conn_set_open(conn);
 
 #ifdef ECP_WITH_PTHREAD
         pthread_mutex_unlock(&conn->mutex);
         pthread_mutex_unlock(&key_next_mutex);
 #endif
-        if (rv) return rv;
 
-        return 1+2*ECP_ECDH_SIZE_KEY;
+        if (_rv) {
+            ecp_conn_close(conn);
+            return _rv;
+        }
+
+        rv = 1+2*ECP_ECDH_SIZE_KEY;
+
 #else   /* ECP_WITH_HTABLE */
 
-        return ECP_ERR_NOT_IMPLEMENTED;
+        ecp_conn_close(conn);
+        rv = ECP_ERR_NOT_IMPLEMENTED;
 
 #endif  /* ECP_WITH_HTABLE */
+
     }
 
-    return ECP_ERR;
+    return rv;
 }
 
 #ifdef ECP_WITH_HTABLE
 static ssize_t vconn_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    ECPBuffer payload;
     ECPConnection *conn_out = NULL;
     ECPVConnIn *conn_v = (ECPVConnIn *)conn;
     ssize_t rv;
 
-    if (conn->out) return ECP_ERR;
     if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR;
+    if (ecp_conn_is_outb(conn)) return ECP_ERR;
     if (b == NULL) return ECP_ERR;
 
     if (size < 0) return size;
@@ -177,13 +195,7 @@ static ssize_t vconn_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned c
 #endif
     conn_out = ecp_ht_search(key_perma_table, conn_v->key_out);
     if (conn_out) {
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn_out->mutex);
-#endif
-        conn_out->refcount++;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn_out->mutex);
-#endif
+        ecp_conn_refcount_inc(conn_out);
     }
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&key_perma_mutex);
@@ -191,20 +203,13 @@ static ssize_t vconn_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned c
 
     if (conn_out == NULL) return ECP_ERR;
 
-    ECPBuffer payload;
     payload.buffer = msg - ECP_SIZE_PLD_HDR - 1;
     payload.size = b->payload->size - (payload.buffer - b->payload->buffer);
 
     ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_EXEC);
     rv = ecp_pld_send(conn_out, b->packet, &payload, ECP_SIZE_PLD_HDR+1+size, ECP_SEND_FLAG_REPLY);
 
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn_out->mutex);
-#endif
-    conn_out->refcount--;
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn_out->mutex);
-#endif
+    ecp_conn_refcount_dec(conn_out);
 
     if (rv < 0) return rv;
     return size;
@@ -234,23 +239,6 @@ static void vlink_remove(ECPConnection *conn) {
 #endif
 }
 
-static int vlink_create(ECPConnection *conn, unsigned char *payload, size_t size) {
-    if (conn->out) return ECP_ERR;
-    if (conn->type != ECP_CTYPE_VLINK) return ECP_ERR;
-
-    // XXX should verify perma_key
-    if (size < ECP_ECDH_SIZE_KEY) return ECP_ERR;
-    ecp_cr_dh_pub_from_buf(&conn->node.public, payload);
-
-    return vlink_insert(conn);
-}
-
-static void vlink_destroy(ECPConnection *conn) {
-    if (conn->out) return;
-    if (conn->type != ECP_CTYPE_VLINK) return;
-
-    vlink_remove(conn);
-}
 #endif  /* ECP_WITH_HTABLE */
 
 static ssize_t _vlink_send_open(ECPConnection *conn, ECPTimerItem *ti) {
@@ -275,68 +263,74 @@ static ssize_t _vlink_send_open(ECPConnection *conn, ECPTimerItem *ti) {
     return ecp_pld_send_wtimer(conn, &packet, &payload, ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1, ECP_MTYPE_OPEN_REQ), 0, ti);
 }
 
-static ssize_t vlink_open(ECPConnection *conn) {
+static ssize_t vlink_send_open(ECPConnection *conn) {
     return ecp_timer_send(conn, _vlink_send_open, ECP_MTYPE_OPEN_REP, 3, 500);
 }
 
-static void vlink_close(ECPConnection *conn) {
-#ifdef ECP_WITH_HTABLE
-    vlink_remove(conn);
-#endif  /* ECP_WITH_HTABLE */
+static ssize_t vlink_handle_kget(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    return _ecp_conn_handle_kget(conn, seq, mtype, msg, size, b, vlink_send_open);
 }
 
 static ssize_t vlink_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
     ssize_t rv;
+    int _rv;
     int is_open;
 
     if (conn->type != ECP_CTYPE_VLINK) return ECP_ERR;
 
     if (size < 0) return size;
 
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn->mutex);
-#endif
-    is_open = ecp_conn_is_open(conn);
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
-#endif
+    if (ecp_conn_is_new(conn) && (size >= 1+ECP_ECDH_SIZE_KEY)) {
+        // XXX we should verify perma_key
+        ecp_cr_dh_pub_from_buf(&conn->node.public, msg+1);
+    }
 
-    rv = ecp_conn_handle_open(conn, seq, mtype, msg, size, b);
+    rv = _ecp_conn_handle_open(conn, seq, mtype, msg, size, b, &is_open);
     if (rv < 0) return rv;
 
     if (mtype & ECP_MTYPE_FLAG_REP) {
-        if (!conn->out) return ECP_ERR;
+
 #ifdef ECP_WITH_HTABLE
-        if (!is_open) {
-            int _rv;
 
+        if (!is_open) {
             _rv = vlink_insert(conn);
             if (_rv) return _rv;
         }
+
 #endif  /* ECP_WITH_HTABLE */
-        return rv;
+
     } else {
-#ifdef ECP_WITH_HTABLE
-        if (conn->out) return ECP_ERR;
         if (size < rv+ECP_ECDH_SIZE_KEY) return ECP_ERR;
 
+#ifdef ECP_WITH_HTABLE
+
         msg += rv;
 
-        // XXX should verify perma_key
-        return rv+ECP_ECDH_SIZE_KEY;
+        if (!is_open) {
+            _rv = vlink_insert(conn);
+            if (_rv) {
+                ecp_conn_close(conn);
+                return _rv;
+            }
+        }
+
+        rv = rv+ECP_ECDH_SIZE_KEY;
 
 #else   /* ECP_WITH_HTABLE */
 
-        return ECP_ERR;
+        ecp_conn_close(conn);
+        rv = ECP_ERR_NOT_IMPLEMENTED;
 
 #endif  /* ECP_WITH_HTABLE */
+
     }
 
-    return ECP_ERR;
+    return rv;
 }
 
 #ifdef ECP_WITH_HTABLE
 static ssize_t vlink_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    ECPBuffer payload;
     ssize_t rv;
 
     if (conn->type != ECP_CTYPE_VLINK) return ECP_ERR;
@@ -350,13 +344,7 @@ static ssize_t vlink_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned c
 #endif
     conn = ecp_ht_search(key_next_table, msg+ECP_SIZE_PROTO+1);
     if (conn) {
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        conn->refcount++;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
+        ecp_conn_refcount_inc(conn);
     }
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&key_next_mutex);
@@ -364,29 +352,58 @@ static ssize_t vlink_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned c
 
     if (conn == NULL) return ECP_ERR;
 
-    ECPBuffer payload;
     payload.buffer = msg - ECP_SIZE_PLD_HDR - 1;
     payload.size = b->payload->size - (payload.buffer - b->payload->buffer);
 
     ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_EXEC);
     rv = ecp_pld_send(conn, b->packet, &payload, ECP_SIZE_PLD_HDR+1+size, ECP_SEND_FLAG_REPLY);
 
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&conn->mutex);
-#endif
-    conn->refcount--;
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
-#endif
+    ecp_conn_refcount_dec(conn);
 
     if (rv < 0) return rv;
     return size;
 }
 #endif  /* ECP_WITH_HTABLE */
 
+#ifdef ECP_MEM_TINY
+/* Memory limited version */
+
+static ssize_t vconn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    if (size < 0) return size;
+    if (b == NULL) return ECP_ERR;
+    if (b->packet->buffer == NULL) return ECP_ERR;
+
+    memcpy(b->packet->buffer, msg, size);
+    return ecp_pkt_handle(conn->sock, NULL, conn, b, size);
+}
+
+#else
+
+static ssize_t vconn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b) {
+    if (size < 0) return size;
+    if (b == NULL) return ECP_ERR;
+
+    ECP2Buffer b2;
+    ECPBuffer packet;
+    ECPBuffer payload;
+    unsigned char pld_buf[ECP_MAX_PLD];
+
+    b2.packet = &packet;
+    b2.payload = &payload;
+
+    packet.buffer = msg;
+    packet.size = b->payload->size - (msg - b->payload->buffer);
+    payload.buffer = pld_buf;
+    payload.size = ECP_MAX_PLD;
+
+    return ecp_pkt_handle(conn->sock, NULL, conn, &b2, size);
+}
+
+#endif
+
 static ssize_t vconn_set_msg(ECPConnection *conn, ECPBuffer *payload, unsigned char mtype) {
-    if (conn->out && (conn->type == ECP_CTYPE_VCONN) && ((mtype == ECP_MTYPE_OPEN_REQ) || (mtype == ECP_MTYPE_KGET_REQ))) {
-        ECPVConnection *conn_v = (ECPVConnection *)conn;
+    if (ecp_conn_is_outb(conn) && (conn->type == ECP_CTYPE_VCONN) && ((mtype == ECP_MTYPE_OPEN_REQ) || (mtype == ECP_MTYPE_KGET_REQ))) {
+        ECPVConnOut *conn_v = (ECPVConnOut *)conn;
         ECPConnection *conn_next = conn_v->next;
         unsigned char *buf = NULL;
         int rv;
@@ -547,31 +564,24 @@ int ecp_vconn_ctx_init(ECPContext *ctx) {
     rv = ecp_conn_handler_init(&handler_vc);
     if (rv) return rv;
 
-#ifdef ECP_WITH_HTABLE
-    handler_vc.conn_create = vconn_create;
-    handler_vc.conn_destroy = vconn_destroy;
-#endif  /* ECP_WITH_HTABLE */
-    handler_vc.conn_open = vconn_open;
     handler_vc.msg[ECP_MTYPE_OPEN] = vconn_handle_open;
-    handler_vc.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec;
+    handler_vc.msg[ECP_MTYPE_KGET] = vconn_handle_kget;
+    handler_vc.msg[ECP_MTYPE_EXEC] = vconn_handle_exec;
 #ifdef ECP_WITH_HTABLE
     handler_vc.msg[ECP_MTYPE_RELAY] = vconn_handle_relay;
+    handler_vc.conn_close = vconn_remove;
 #endif  /* ECP_WITH_HTABLE */
     ctx->handler[ECP_CTYPE_VCONN] = &handler_vc;
 
     rv = ecp_conn_handler_init(&handler_vl);
     if (rv) return rv;
 
-#ifdef ECP_WITH_HTABLE
-    handler_vl.conn_create = vlink_create;
-    handler_vl.conn_destroy = vlink_destroy;
-#endif  /* ECP_WITH_HTABLE */
-    handler_vl.conn_open = vlink_open;
-    handler_vl.conn_close = vlink_close;
     handler_vl.msg[ECP_MTYPE_OPEN] = vlink_handle_open;
-    handler_vl.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec;
+    handler_vl.msg[ECP_MTYPE_KGET] = vlink_handle_kget;
+    handler_vl.msg[ECP_MTYPE_EXEC] = vconn_handle_exec;
 #ifdef ECP_WITH_HTABLE
     handler_vl.msg[ECP_MTYPE_RELAY] = vlink_handle_relay;
+    handler_vl.conn_close = vlink_remove;
 #endif  /* ECP_WITH_HTABLE */
     ctx->handler[ECP_CTYPE_VLINK] = &handler_vl;
 
@@ -605,21 +615,23 @@ int ecp_vconn_ctx_init(ECPContext *ctx) {
     return ECP_OK;
 }
 
-int ecp_vconn_set_remote(ECPConnection *conn, ECPNode *conn_node, ECPVConnection vconn[], ECPNode vconn_node[], int size) {
+int ecp_vconn_create_parent(ECPConnection *conn, ECPNode *conn_node, ECPVConnOut vconn[], ECPNode vconn_node[], int size) {
     ECPSocket *sock = conn->sock;
-    int i, rv;
-
-    rv = ecp_conn_set_remote(conn, conn_node);
-    if (rv) return rv;
+    int i, j, rv;
 
     conn->parent = (ECPConnection *)&vconn[size-1];
     conn->pcount = size;
     for (i=0; i<size; i++) {
-        rv = ecp_conn_create((ECPConnection *)&vconn[i], sock, ECP_CTYPE_VCONN);
-        if (rv) return rv;
-
-        rv = ecp_conn_set_remote((ECPConnection *)&vconn[i], &vconn_node[i]);
-        if (rv) return rv;
+        rv = ecp_conn_init((ECPConnection *)&vconn[i], sock, ECP_CTYPE_VCONN);
+        if (!rv) rv = ecp_conn_create_outb((ECPConnection *)&vconn[i], &vconn_node[i]);
+        if (!rv) {
+            rv = ecp_conn_insert((ECPConnection *)&vconn[i]);
+            if (rv) ecp_conn_destroy((ECPConnection *)&vconn[i]);
+        }
+        if (rv) {
+            for (j=0; j<i; j++) ecp_conn_close((ECPConnection *)&vconn[j]);
+            return rv;
+        }
 
         if (i == 0) {
             vconn[i].b.parent = NULL;
@@ -653,13 +665,25 @@ static ssize_t _vconn_send_kget(ECPConnection *conn, ECPTimerItem *ti) {
     return _ecp_pld_send(conn, &packet, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, NULL, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_KGET_REQ), 0, ti);
 }
 
-int ecp_vconn_open(ECPConnection *conn, ECPNode *conn_node, ECPVConnection vconn[], ECPNode vconn_node[], int size) {
+int ecp_vconn_open(ECPConnection *conn, ECPNode *conn_node, ECPVConnOut vconn[], ECPNode vconn_node[], int size) {
     int rv;
     ssize_t _rv;
 
-    rv = ecp_vconn_set_remote(conn, conn_node, vconn, vconn_node, size);
+    rv = ecp_conn_create_outb(conn, conn_node);
     if (rv) return rv;
 
+    rv = ecp_conn_insert(conn);
+    if (rv) {
+        ecp_conn_destroy(conn);
+        return rv;
+    }
+
+    rv = ecp_vconn_create_parent(conn, conn_node, vconn, vconn_node, size);
+    if (rv) {
+        ecp_conn_close(conn);
+        return rv;
+    }
+
     _rv = ecp_timer_send((ECPConnection *)&vconn[0], _vconn_send_kget, ECP_MTYPE_KGET_REP, 3, 500);
     if (_rv < 0) return _rv;
 
diff --git a/ecp/src/vconn/vconn.h b/ecp/src/vconn/vconn.h
index 12eae77..73d9fd6 100644
--- a/ecp/src/vconn/vconn.h
+++ b/ecp/src/vconn/vconn.h
@@ -4,10 +4,10 @@
 #define ECP_MTYPE_RELAY     0x08
 #define ECP_MTYPE_EXEC      0x09
 
-typedef struct ECPVConnection {
+typedef struct ECPVConnOut {
     ECPConnection b;
     ECPConnection *next;
-} ECPVConnection;
+} ECPVConnOut;
 
 typedef struct ECPVConnIn {
     ECPConnection b;
@@ -16,6 +16,7 @@ typedef struct ECPVConnIn {
     unsigned char key_out[ECP_ECDH_SIZE_KEY];
 } ECPVConnIn;
 
+ssize_t ecp_vconn_handle_exec(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size, ECP2Buffer *b);
 int ecp_vconn_ctx_init(ECPContext *ctx);
-int ecp_vconn_set_remote(ECPConnection *conn, ECPNode *conn_node, ECPVConnection vconn[], ECPNode vconn_node[], int size);
-int ecp_vconn_open(ECPConnection *conn, ECPNode *conn_node, ECPVConnection vconn[], ECPNode vconn_node[], int size);
+int ecp_vconn_create_parent(ECPConnection *conn, ECPNode *conn_node, ECPVConnOut vconn[], ECPNode vconn_node[], int size);
+int ecp_vconn_open(ECPConnection *conn, ECPNode *conn_node, ECPVConnOut vconn[], ECPNode vconn_node[], int size);
diff --git a/ecp/test/basic.c b/ecp/test/basic.c
index eb14b0e..0f4e322 100644
--- a/ecp/test/basic.c
+++ b/ecp/test/basic.c
@@ -68,8 +68,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_s, &key_perma_s);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_s, &ctx_s, &key_perma_s);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_s, &ctx_s, &key_perma_s);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_s, "0.0.0.0:3000");
     printf("ecp_sock_open RV:%d\n", rv);
@@ -88,8 +88,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_c, &key_perma_c);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_c, &ctx_c, &key_perma_c);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_c, &ctx_c, &key_perma_c);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_c, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -100,8 +100,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_node_init(&node, &key_perma_s.public, "127.0.0.1:3000");
     printf("ecp_node_init RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock_c, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock_c, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_conn_open(&conn, &node);
     printf("ecp_conn_open RV:%d\n", rv);
diff --git a/ecp/test/client.c b/ecp/test/client.c
index e6c8208..577a888 100644
--- a/ecp/test/client.c
+++ b/ecp/test/client.c
@@ -58,8 +58,8 @@ int main(int argc, char *argv[]) {
     handler.msg[MTYPE_MSG] = handle_msg;
     ctx.handler[CTYPE_TEST] = &handler;
     
-    rv = ecp_sock_create(&sock, &ctx, NULL);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock, &ctx, NULL);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -70,8 +70,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_util_node_load(&ctx, &node, argv[1]);
     printf("ecp_util_node_load RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_conn_open(&conn, &node);
     printf("ecp_conn_open RV:%d\n", rv);
diff --git a/ecp/test/dir.c b/ecp/test/dir.c
index 413cd03..0c2ac72 100644
--- a/ecp/test/dir.c
+++ b/ecp/test/dir.c
@@ -5,6 +5,7 @@
 #include "core.h"
 #include "cr.h"
 #include "dir.h"
+#include "dir_srv.h"
 
 ECPContext ctx_s;
 ECPSocket sock_s;
@@ -51,8 +52,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_s, &key_perma_s);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_s, &ctx_s, &key_perma_s);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_s, &ctx_s, &key_perma_s);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_s, "0.0.0.0:3000");
     printf("ecp_sock_open RV:%d\n", rv);
@@ -70,8 +71,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_c, &key_perma_c);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_c, &ctx_c, &key_perma_c);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_c, &ctx_c, &key_perma_c);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_c, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -82,8 +83,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_node_init(&node, &key_perma_s.public, "127.0.0.1:3000");
     printf("ecp_node_init RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock_c, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock_c, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_conn_get_dirlist(&conn, &node);
     printf("ecp_conn_get_dirlist RV:%d\n", rv);
diff --git a/ecp/test/echo.c b/ecp/test/echo.c
index ff9c01c..f3057df 100644
--- a/ecp/test/echo.c
+++ b/ecp/test/echo.c
@@ -43,8 +43,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_util_key_load(&ctx_s, &key_perma_s, argv[2]);
     printf("ecp_util_key_load RV:%d\n", rv);
     
-    rv = ecp_sock_create(&sock_s, &ctx_s, &key_perma_s);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_s, &ctx_s, &key_perma_s);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_s, argv[1]);
     printf("ecp_sock_open RV:%d\n", rv);
diff --git a/ecp/test/frag.c b/ecp/test/frag.c
index bf7c1a2..73e45cb 100644
--- a/ecp/test/frag.c
+++ b/ecp/test/frag.c
@@ -74,8 +74,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_s, &key_perma_s);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_s, &ctx_s, &key_perma_s);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_s, &ctx_s, &key_perma_s);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_s, "0.0.0.0:3000");
     printf("ecp_sock_open RV:%d\n", rv);
@@ -94,8 +94,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_dhkey_gen(&ctx_c, &key_perma_c);
     printf("ecp_dhkey_gen RV:%d\n", rv);
 
-    rv = ecp_sock_create(&sock_c, &ctx_c, &key_perma_c);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_c, &ctx_c, &key_perma_c);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_c, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -106,8 +106,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_node_init(&node, &key_perma_s.public, "127.0.0.1:3000");
     printf("ecp_node_init RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock_c, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock_c, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_rbuf_create(&conn, NULL, NULL, 0, &rbuf_recv, rbuf_r_msg, 128);
     printf("ecp_rbuf_create RV:%d\n", rv);
diff --git a/ecp/test/init.c b/ecp/test/init.c
index 4dff693..7b59578 100644
--- a/ecp/test/init.c
+++ b/ecp/test/init.c
@@ -14,8 +14,19 @@ static int v_rng(void *buf, size_t bufsize) {
     return 0;
 }
 
-static ECPConnection *conn_alloc(unsigned char type) {
-    return malloc(sizeof(ECPConnection));
+static ECPConnection *conn_alloc(ECPSocket *sock, unsigned char type) {
+    ECPConnection *conn;
+    int rv;
+
+    conn = malloc(sizeof(ECPConnection));
+    if (conn == NULL) return NULL;
+
+    rv = ecp_conn_init(conn, sock, type);
+    if (rv) {
+        free(conn);
+        return NULL;
+    }
+    return conn;
 }
 
 static void conn_free(ECPConnection *conn) {
diff --git a/ecp/test/init_vconn.c b/ecp/test/init_vconn.c
index b79aa3d..59e9517 100644
--- a/ecp/test/init_vconn.c
+++ b/ecp/test/init_vconn.c
@@ -15,16 +15,31 @@ static int v_rng(void *buf, size_t bufsize) {
     return 0;
 }
 
-static ECPConnection *conn_alloc(unsigned char type) {
+static ECPConnection *conn_alloc(ECPSocket *sock, unsigned char type) {
+    ECPConnection *conn;
+    int rv;
+
     switch (type) {
         case ECP_CTYPE_VCONN:
-            return malloc(sizeof(ECPVConnIn));
+            conn = malloc(sizeof(ECPVConnIn));
+            break;
         default:
-            return malloc(sizeof(ECPConnection));
+            conn = malloc(sizeof(ECPConnection));
+            break;
+    }
+    if (conn == NULL) return NULL;
+
+    rv = ecp_conn_init(conn, sock, type);
+    if (rv) {
+        printf("free1\n");
+        free(conn);
+        return NULL;
     }
+    return conn;
 }
 
 static void conn_free(ECPConnection *conn) {
+    printf("free2\n");
     free(conn);
 }
 
diff --git a/ecp/test/server.c b/ecp/test/server.c
index f70cc79..fabaf4e 100644
--- a/ecp/test/server.c
+++ b/ecp/test/server.c
@@ -46,8 +46,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_util_key_load(&ctx, &key_perma, argv[2]);
     printf("ecp_util_key_load RV:%d\n", rv);
     
-    rv = ecp_sock_create(&sock, &ctx, &key_perma);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock, &ctx, &key_perma);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, argv[1]);
     printf("ecp_sock_open RV:%d\n", rv);
diff --git a/ecp/test/stress.c b/ecp/test/stress.c
index 4dae990..6eed851 100644
--- a/ecp/test/stress.c
+++ b/ecp/test/stress.c
@@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
     if (!rv) rv = ecp_dhkey_gen(&ctx_s, &key_perma_s);
 
     for (i=0; i<num_s; i++) {
-        if (!rv) rv = ecp_sock_create(&sock_s[i], &ctx_s, &key_perma_s);
+        if (!rv) rv = ecp_sock_init(&sock_s[i], &ctx_s, &key_perma_s);
 
         strcpy(addr, "0.0.0.0:");
         sprintf(addr+strlen(addr), "%d", 3000+i);
@@ -230,7 +230,7 @@ int main(int argc, char *argv[]) {
         ctx_c[i].handler[CTYPE_TEST] = &handler_c;
 
         if (!rv) rv = ecp_dhkey_gen(&ctx_c[i], &key_perma_c[i]);
-        if (!rv) rv = ecp_sock_create(&sock_c[i], &ctx_c[i], &key_perma_c[i]);
+        if (!rv) rv = ecp_sock_init(&sock_c[i], &ctx_c[i], &key_perma_c[i]);
         if (!rv) rv = ecp_sock_open(&sock_c[i], NULL);
 
         if (!rv) rv = pthread_create(&r_thd[i], NULL, (void *(*)(void *))ecp_receiver, (void *)&sock_c[i]);
@@ -239,7 +239,7 @@ int main(int argc, char *argv[]) {
         sprintf(addr+strlen(addr), "%d", 3000 + (i % num_s));
         if (!rv) rv = ecp_node_init(&node[i], &key_perma_s.public, addr);
 
-        if (!rv) rv = ecp_conn_create(&conn[i], &sock_c[i], CTYPE_TEST);
+        if (!rv) rv = ecp_conn_init(&conn[i], &sock_c[i], CTYPE_TEST);
         conn[i].conn_data = (void *)i;
 
         if (!rv) rv = ecp_conn_open(&conn[i], &node[i]);
diff --git a/ecp/test/vc_client.c b/ecp/test/vc_client.c
index d669697..cd0ea44 100644
--- a/ecp/test/vc_client.c
+++ b/ecp/test/vc_client.c
@@ -14,7 +14,7 @@ ECPConnHandler handler;
 ECPConnection conn;
 ECPNode node;
 
-ECPVConnection vconn[20];
+ECPVConnOut vconn[20];
 ECPNode vconn_node[20];
 
 #define CTYPE_TEST  0
@@ -63,8 +63,8 @@ int main(int argc, char *argv[]) {
     handler.msg[MTYPE_MSG] = handle_msg;
     ctx.handler[CTYPE_TEST] = &handler;
 
-    rv = ecp_sock_create(&sock, &ctx, NULL);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock, &ctx, NULL);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -80,8 +80,8 @@ int main(int argc, char *argv[]) {
         printf("ecp_util_node_load RV:%d\n", rv);
     }
 
-    rv = ecp_conn_create(&conn, &sock, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_vconn_open(&conn, &node, vconn, vconn_node, argc-2);
     printf("ecp_vconn_open RV:%d\n", rv);
diff --git a/ecp/test/vc_client_t.c b/ecp/test/vc_client_t.c
index b021c2d..968d643 100644
--- a/ecp/test/vc_client_t.c
+++ b/ecp/test/vc_client_t.c
@@ -15,7 +15,7 @@ ECPConnHandler handler;
 ECPNode node;
 ECPConnection conn;
 
-ECPVConnection vconn[20];
+ECPVConnOut vconn[20];
 ECPNode vconn_node[20];
 
 #define CTYPE_TEST  0
@@ -80,23 +80,23 @@ static void usage(char *arg) {
 
 int main(int argc, char *argv[]) {
     int rv, i;
-    
+
     if ((argc < 3) || (argc > 22)) usage(argv[0]);
-    
+
     rv = ecp_init(&ctx);
     printf("ecp_init RV:%d\n", rv);
-    
+
     rv = ecp_conn_handler_init(&handler);
     handler.msg[ECP_MTYPE_OPEN] = handle_open;
     handler.msg[MTYPE_MSG] = handle_msg;
     ctx.handler[CTYPE_TEST] = &handler;
-    
-    rv = ecp_sock_create(&sock, &ctx, NULL);
-    printf("ecp_sock_create RV:%d\n", rv);
+
+    rv = ecp_sock_init(&sock, &ctx, NULL);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
-    
+
     rv = ecp_start_receiver(&sock);
     printf("ecp_start_receiver RV:%d\n", rv);
 
@@ -108,8 +108,8 @@ int main(int argc, char *argv[]) {
         printf("ecp_util_node_load RV:%d\n", rv);
     }
 
-    rv = ecp_conn_create(&conn, &sock, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_vconn_open(&conn, &node, vconn, vconn_node, argc-2);
     printf("ecp_vconn_open RV:%d\n", rv);
diff --git a/ecp/test/vc_server.c b/ecp/test/vc_server.c
index 55f15d1..b86d7b0 100644
--- a/ecp/test/vc_server.c
+++ b/ecp/test/vc_server.c
@@ -24,7 +24,7 @@ ssize_t handle_open(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned
 }
 
 ssize_t handle_msg(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s, ECP2Buffer *b) {
-    // printf("MSG S:%s size:%ld\n", p, s);
+    printf("MSG S:%s size:%ld\n", p, s);
 
     char *msg = "VAISTINU JE CAR!";
     unsigned char buf[1000];
@@ -42,34 +42,34 @@ static void usage(char *arg) {
 
 int main(int argc, char *argv[]) {
     int rv;
-    
+
     if (argc != 3) usage(argv[0]);
-    
+
     rv = ecp_init(&ctx);
     printf("ecp_init RV:%d\n", rv);
-    
+
     rv = ecp_conn_handler_init(&handler);
     handler.msg[ECP_MTYPE_OPEN] = handle_open;
     handler.msg[MTYPE_MSG] = handle_msg;
     ctx.handler[CTYPE_TEST] = &handler;
-    
+
     rv = ecp_util_key_load(&ctx, &key_perma, argv[1]);
     printf("ecp_util_key_load RV:%d\n", rv);
-    
-    rv = ecp_sock_create(&sock, &ctx, &key_perma);
-    printf("ecp_sock_create RV:%d\n", rv);
+
+    rv = ecp_sock_init(&sock, &ctx, &key_perma);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
-    
+
     rv = ecp_start_receiver(&sock);
     printf("ecp_start_receiver RV:%d\n", rv);
 
     rv = ecp_util_node_load(&ctx, &node, argv[2]);
     printf("ecp_util_node_load RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock, ECP_CTYPE_VLINK);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock, ECP_CTYPE_VLINK);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_conn_open(&conn, &node);
     printf("ecp_conn_open RV:%d\n", rv);
diff --git a/ecp/test/vcs.c b/ecp/test/vcs.c
index 23e2557..f3a0156 100644
--- a/ecp/test/vcs.c
+++ b/ecp/test/vcs.c
@@ -30,8 +30,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_util_key_load(&ctx, &key_perma, argv[2]);
     printf("ecp_util_key_load RV:%d\n", rv);
     
-    rv = ecp_sock_create(&sock, &ctx, &key_perma);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock, &ctx, &key_perma);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock, argv[1]);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -43,8 +43,8 @@ int main(int argc, char *argv[]) {
         rv = ecp_util_node_load(&ctx, &node, argv[3]);
         printf("ecp_util_node_load RV:%d\n", rv);
 
-        rv = ecp_conn_create(&conn, &sock, ECP_CTYPE_VLINK);
-        printf("ecp_conn_create RV:%d\n", rv);
+        rv = ecp_conn_init(&conn, &sock, ECP_CTYPE_VLINK);
+        printf("ecp_conn_init RV:%d\n", rv);
 
         rv = ecp_conn_open(&conn, &node);
         printf("ecp_conn_open RV:%d\n", rv);
diff --git a/ecp/test/voip.c b/ecp/test/voip.c
index ad5032b..b0a9207 100644
--- a/ecp/test/voip.c
+++ b/ecp/test/voip.c
@@ -163,8 +163,8 @@ int main(int argc, char *argv[]) {
     handler_c.msg[MTYPE_MSG] = handle_msg_c;
     ctx_c.handler[CTYPE_TEST] = &handler_c;
     
-    rv = ecp_sock_create(&sock_c, &ctx_c, NULL);
-    printf("ecp_sock_create RV:%d\n", rv);
+    rv = ecp_sock_init(&sock_c, &ctx_c, NULL);
+    printf("ecp_sock_init RV:%d\n", rv);
 
     rv = ecp_sock_open(&sock_c, NULL);
     printf("ecp_sock_open RV:%d\n", rv);
@@ -175,8 +175,8 @@ int main(int argc, char *argv[]) {
     rv = ecp_util_node_load(&ctx_c, &node, argv[1]);
     printf("ecp_util_node_load RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock_c, CTYPE_TEST);
-    printf("ecp_conn_create RV:%d\n", rv);
+    rv = ecp_conn_init(&conn, &sock_c, CTYPE_TEST);
+    printf("ecp_conn_init RV:%d\n", rv);
 
     rv = ecp_conn_open(&conn, &node);
     printf("ecp_conn_open RV:%d\n", rv);
-- 
cgit v1.2.3