From 7c70a430f9c708be2fcce8c9a0d8cecde7f75fc0 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Tue, 23 May 2017 03:49:54 +0200
Subject: changes for proxy

---
 code/Makefile      |   4 +-
 code/TODO          |   6 +
 code/core.c        | 641 +++++++++++++++++++++++++++++------------------------
 code/core.h        | 113 +++++++---
 code/init.c        |   2 +-
 code/msgq.c        |  59 ++---
 code/msgq.h        |  14 +-
 code/test/Makefile |   2 +-
 code/test/server.c |  46 ++--
 code/test/stress.c |  53 +++--
 code/timer.c       |  44 ++--
 code/timer.h       |  12 +-
 12 files changed, 554 insertions(+), 442 deletions(-)

(limited to 'code')

diff --git a/code/Makefile b/code/Makefile
index 023fa7a..be1a827 100644
--- a/code/Makefile
+++ b/code/Makefile
@@ -1,12 +1,12 @@
 MAKE=make
 CFLAGS = -I. -pthread -O3 -DECP_DEBUG
-obj = core.o timer.o msgq.o init.o
+obj = core.o timer.o msgq.o
 subdirs = crypto posix htable test
 
 %.o: %.c %.h
 	$(CC) $(CFLAGS) -c $<
 
-all: $(obj)
+all: $(obj) init.o init_proxy.o
 	$(AR) rcs libecpcore.a $(obj)
 	for i in $(subdirs); do \
 		(cd $$i && $(MAKE) && cd ..) || exit; \
diff --git a/code/TODO b/code/TODO
index c911866..1795089 100644
--- a/code/TODO
+++ b/code/TODO
@@ -3,3 +3,9 @@
 
 - memzero keys after usage
 - implement socket message queue
+
+proxy:
+- implement init
+core:
+- msgq marker
+- implement exec
diff --git a/code/core.c b/code/core.c
index ced4c01..821487e 100644
--- a/code/core.c
+++ b/code/core.c
@@ -22,29 +22,6 @@ int ecp_node_init(ECPContext *ctx, ECPNode *node, void *addr, ecp_dh_public_t *p
     return ECP_OK;
 }
 
-ssize_t ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size) {
-    ssize_t rv;
-
-    if (packet == NULL) return ECP_ERR;
-    if (payload == NULL) return ECP_ERR;
-
-    packet[0] = 0;
-    packet[1] = 0;
-    s_idx = s_idx & 0x0F;
-    c_idx = c_idx & 0x0F;
-    packet[ECP_SIZE_PROTO] = (s_idx << 4) | c_idx;
-    ctx->cr.dh_pub_to_buf(packet+ECP_SIZE_PROTO+1, public);
-    memcpy(packet+ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY, nonce, ECP_AEAD_SIZE_NONCE);
-
-    memcpy(payload, seq, ECP_SIZE_SEQ);
-    rv = ctx->cr.aead_enc(packet+ECP_SIZE_PKT_HDR, pkt_size-ECP_SIZE_PKT_HDR, payload, payload_size, shsec, packet+ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY);
-    if (rv < 0) return ECP_ERR_ENCRYPT;
-    
-    memcpy(nonce, packet+ECP_SIZE_PKT_HDR, ECP_AEAD_SIZE_NONCE);
-        
-    return rv+ECP_SIZE_PKT_HDR;
-}
-    
 int ecp_ctx_create(ECPContext *ctx) {
     int rv;
     
@@ -184,10 +161,6 @@ static ECPConnection *ctable_search(ECPSocket *sock, unsigned char c_idx, unsign
     return NULL;
 }
 
-static ssize_t conn_handle_open(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size);
-static ssize_t conn_handle_kget(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size);
-static ssize_t conn_handle_kput(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size);
-
 int ecp_sock_create(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key) {
     int rv = ECP_OK; 
     
@@ -200,9 +173,7 @@ int ecp_sock_create(ECPSocket *sock, ECPContext *ctx, ECPDHKey *key) {
     sock->poll_timeout = ECP_POLL_TIMEOUT;
     sock->key_curr = 0;
     sock->key_perma = *key;
-    sock->handler[ECP_PTYPE_OPEN] = conn_handle_open;
-    sock->handler[ECP_PTYPE_KGET] = conn_handle_kget;
-    sock->handler[ECP_PTYPE_KPUT] = conn_handle_kput;
+    sock->conn_new = ecp_conn_handle_new;
 
     rv = ecp_dhkey_generate(sock->ctx, &sock->key[sock->key_curr]);
     if (!rv) rv = ctable_create(&sock->conn, sock->ctx);
@@ -246,7 +217,7 @@ int ecp_sock_dhkey_get_curr(ECPSocket *sock, unsigned char *idx, unsigned char *
     pthread_mutex_lock(&sock->mutex);
 #endif
 
-    *idx = sock->key_curr;
+    if (idx) *idx = sock->key_curr;
     if (*idx != ECP_ECDH_IDX_INV) sock->ctx->cr.dh_pub_to_buf(public, &sock->key[sock->key_curr].public);
 
 #ifdef ECP_WITH_PTHREAD
@@ -425,148 +396,7 @@ static int conn_shsec_set(ECPConnection *conn, unsigned char s_idx, unsigned cha
     return ECP_OK;
 }
 
-
-static int conn_new(ECPConnection **_conn, ECPSocket *sock, unsigned char s_idx, unsigned char c_idx, unsigned char *c_public, ecp_aead_key_t *shsec, unsigned char *payload, size_t payload_size) {
-    ECPConnection *conn = NULL;
-    int rv = ECP_OK;
-    
-    if (_conn == NULL) return ECP_ERR;
-    if (sock == NULL) return ECP_ERR;
-
-    conn = sock->ctx->conn_alloc ? sock->ctx->conn_alloc() : NULL;
-    if (conn == NULL) return ECP_ERR_ALLOC;
-
-    rv = ecp_conn_create(conn, sock);
-    if (rv) {
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
-    conn->refcount = 1;
-    rv = conn_dhkey_new_pub_local(conn, s_idx);
-    if (!rv) rv = conn_dhkey_new_pub_remote(conn, c_idx, c_public);
-    if (!rv) rv = conn_shsec_set(conn, s_idx, c_idx, shsec);
-    if (!rv && sock->conn_create) rv = sock->conn_create(conn, payload, payload_size);
-    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 (sock->conn_destroy) sock->conn_destroy(conn);
-        ecp_conn_destroy(conn);
-        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
-        return rv;
-    }
-
-    *_conn = conn;
-    return rv;
-}
-
-static ssize_t conn_handle_open(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size) {
-    ecp_conn_handler_t *handler = conn->handler ? conn->handler->f[ptype] : NULL;
-
-    if (conn->out) {
-        if (size < 0) return handler ? handler(conn, ptype, payload, size) : 0;
-
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        if (!ecp_conn_is_open(conn)) conn->flags |= ECP_CONN_FLAG_OPEN;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
-
-        return handler ? handler(conn, ptype, payload, size) : 0;
-    } else {
-        if (size < 0) return ECP_ERR;
-
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        if (!ecp_conn_is_open(conn)) conn->flags |= ECP_CONN_FLAG_OPEN;
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
-
-        ssize_t _rv = ecp_send(conn, ECP_PTYPE_OPEN, NULL, 0);
-
-        return handler ? handler(conn, ptype, payload, size) : 0;
-    }
-
-    return ECP_ERR;
-}
-
-static ssize_t conn_handle_kget(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size) {
-    ecp_conn_handler_t *handler = conn->handler ? conn->handler->f[ptype] : NULL;
-
-    if (conn->out) {
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&conn->mutex);
-#endif
-        int conn_is_open = ecp_conn_is_open(conn);
-#ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-#endif
-
-        if (size < 0) {
-            if (!conn_is_open) handler = conn->handler ? conn->handler->f[ECP_PTYPE_OPEN] : handler;
-            return handler ? handler(conn, ptype, payload, size) : 0;
-        }
-
-        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
-
-        int rv = ecp_conn_dhkey_new_pub(conn, payload[0], payload+1);
-        if (!rv && !conn_is_open) {
-            ECPTimerItem ti;
-            ssize_t _rv = 0;
-
-            rv = ecp_timer_item_init(&ti, conn, ECP_PTYPE_OPEN, 3, 500);
-            if (!rv) rv = ecp_timer_push(conn, &ti);
-            if (!rv) _rv = ecp_send(conn, ECP_PTYPE_OPEN, NULL, 0);
-            if (_rv < 0) rv = _rv;
-        }
-
-        return handler ? handler(conn, ptype, rv ? NULL : payload, rv ? rv : size) : ECP_ECDH_SIZE_KEY+1;
-    } else {
-        unsigned char payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)];
-        unsigned char *buf = ecp_pld_get_buf(payload);
-        ecp_pld_set_type(payload, ECP_PTYPE_KGET);
-
-        if (size < 0) return ECP_ERR;
-
-        int rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
-        if (rv) return rv;
-        
-        ssize_t _rv = ecp_pld_send(conn, payload, sizeof(payload));
-
-        return handler ? handler(conn, ptype, payload, size) : 0;
-    }
-
-    return ECP_ERR;
-}
- 
-static ssize_t conn_handle_kput(ECPConnection *conn, unsigned char ptype, unsigned char *payload, ssize_t size) {
-    ecp_conn_handler_t *handler = conn->handler ? conn->handler->f[ptype] : NULL;
-
-    if (conn->out) {
-        return handler ? handler(conn, ptype, payload, size) : 0;
-    } else {
-        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
-
-        int rv = ecp_conn_dhkey_new_pub(conn, payload[0], payload+1);
-        if (rv) return rv;
-
-        ssize_t _rv = ecp_send(conn, ECP_PTYPE_KPUT, NULL, 0);
-
-        return handler ? handler(conn, ptype, payload, size) : ECP_ECDH_SIZE_KEY+1;
-    }
-
-    return ECP_ERR;
-}
-
-int ecp_conn_create(ECPConnection *conn, ECPSocket *sock) {
+int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
     int i;
     
     if (conn == NULL) return ECP_ERR;
@@ -574,6 +404,9 @@ int ecp_conn_create(ECPConnection *conn, ECPSocket *sock) {
 
     memset(conn, 0, sizeof(ECPConnection));
 
+    if (ctype >= ECP_MAX_CTYPE) return ECP_ERR_MAX_CTYPE;
+        
+    conn->type = ctype;
     conn->key_curr = ECP_ECDH_IDX_INV;
     conn->key_idx_curr = ECP_ECDH_IDX_INV;
     conn->remote.key_curr = ECP_ECDH_IDX_INV;
@@ -623,9 +456,8 @@ int ecp_conn_register(ECPConnection *conn) {
     return rv;
 }
 
-int ecp_conn_unregister(ECPConnection *conn, unsigned int timeout) {
+void ecp_conn_unregister(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
-    int refcount = 0;
 
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&sock->conn.mutex);
@@ -639,7 +471,57 @@ int ecp_conn_unregister(ECPConnection *conn, unsigned int timeout) {
     pthread_mutex_unlock(&conn->mutex);
     pthread_mutex_unlock(&sock->conn.mutex);
 #endif
+}
+
+static ssize_t _conn_send_kget(ECPConnection *conn, ECPTimerItem *ti) {
+    unsigned char payload[ECP_SIZE_PLD(0)];
 
+    ecp_pld_set_type(payload, ECP_MTYPE_KGET);
+    return ecp_pld_send_wkey(conn, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, payload, sizeof(payload));
+}
+
+int ecp_conn_init(ECPConnection *conn, ECPNode *node) {
+    ECPDHKey key;
+    ECPContext *ctx = conn->sock->ctx;
+    int rv = ECP_OK;
+
+    if (conn == NULL) return ECP_ERR;
+    if (node == NULL) return ECP_ERR;
+    if (ctx->rng == NULL) return ECP_ERR_RNG;
+
+    conn->out = 1;
+    conn->node = *node;
+    rv = ctx->rng(conn->nonce, ECP_AEAD_SIZE_NONCE);
+    if (!rv) rv = ecp_dhkey_generate(ctx, &key);
+    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_open(ECPConnection *conn, ECPNode *node) {
+    int rv = ecp_conn_init(conn, node);
+    if (rv) return rv;
+    
+    ssize_t _rv = ecp_timer_send(conn, _conn_send_kget, ECP_MTYPE_KGET, 3, 500);
+    if (_rv < 0) {
+        ecp_conn_unregister(conn);
+        return _rv;
+    }
+
+    return ECP_OK;
+}
+
+int ecp_conn_close(ECPConnection *conn, unsigned int timeout) {
+    ECPSocket *sock = conn->sock;
+    int refcount = 0;
+    
+    if (!conn->out) {
+        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 (sock->conn_destroy) sock->conn_destroy(conn);
+    }
+    ecp_conn_unregister(conn);
     ecp_timer_remove(conn);
 
 #ifdef ECP_WITH_PTHREAD
@@ -657,91 +539,223 @@ int ecp_conn_unregister(ECPConnection *conn, unsigned int timeout) {
     if (refcount) return ECP_ERR_TIMEOUT;
 #endif
 
+    if (!conn->out) {
+        if (conn->proxy) {
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_lock(&conn->proxy->mutex);
+#endif
+            conn->proxy->refcount--;
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_unlock(&conn->proxy->mutex);
+#endif
+        }
+        ecp_conn_destroy(conn);
+        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
+    }
+    
     return ECP_OK;
 }
 
-static int _conn_kget_send(ECPConnection *conn, ECPTimerItem *ti) {
-    unsigned char payload[ECP_MIN_PLD];
-    ecp_pld_set_type(payload, ECP_PTYPE_KGET);
-    ssize_t rv = ecp_pld_send_wkey(conn, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, payload, sizeof(payload));
-    if (rv < 0) return rv;
+int ecp_conn_handler_init(ECPConnHandler *handler) {
+    memset(handler, 0, sizeof(ECPConnHandler));
+    handler->msg[ECP_MTYPE_OPEN] = ecp_conn_handle_open;
+    handler->msg[ECP_MTYPE_KGET] = ecp_conn_handle_kget;
+    handler->msg[ECP_MTYPE_KPUT] = ecp_conn_handle_kput;
+    handler->conn_open = ecp_conn_send_open;
     return ECP_OK;
 }
 
-int ecp_conn_open(ECPConnection *conn, ECPNode *node, ECPConnHandler *handler) {
+static ssize_t _conn_send_open(ECPConnection *conn, ECPTimerItem *ti) {
+    unsigned char payload[ECP_SIZE_PLD(1)];
+    unsigned char *buf = ecp_pld_get_buf(payload);
+    
+    ecp_pld_set_type(payload, ECP_MTYPE_OPEN);
+    buf[0] = conn->type;
+    
+    return ecp_pld_send(conn, payload, sizeof(payload));
+}
+
+ssize_t ecp_conn_send_open(ECPConnection *conn) {
+    return ecp_timer_send(conn, _conn_send_open, ECP_MTYPE_OPEN, 3, 500);
+}
+
+int ecp_conn_handle_new(ECPSocket *sock, ECPConnection **_conn, ECPConnection *proxy, unsigned char s_idx, unsigned char c_idx, unsigned char *c_public, ecp_aead_key_t *shsec, unsigned char *payload, size_t payload_size) {
+    ECPConnection *conn = NULL;
     int rv = ECP_OK;
-    ECPDHKey key;
-    ECPContext *ctx = conn->sock->ctx;
+    unsigned char ctype = 0;
+    ecp_conn_create_t *handle_create = NULL;
+    ecp_conn_destroy_t *handle_destroy = NULL;
     
-    if (conn == NULL) return ECP_ERR;
-    if (node == NULL) return ECP_ERR;
-    if (ctx->rng == NULL) return ECP_ERR_RNG;
+    if (payload_size < 1) return ECP_ERR;
+    
+    conn = sock->ctx->conn_alloc ? sock->ctx->conn_alloc(ctype) : NULL;
+    if (conn == NULL) return ECP_ERR_ALLOC;
 
-    conn->out = 1;
-    conn->node = *node;
-    conn->handler = handler;
-    rv = ctx->rng(conn->nonce, ECP_AEAD_SIZE_NONCE);
-    if (!rv) rv = ecp_dhkey_generate(ctx, &key);
-    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);
-    if (rv) return rv;
+    ctype = payload[0];
+    rv = ecp_conn_create(conn, sock, ctype);
+    if (rv) {
+        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
+        return rv;
+    }
     
-    rv = ecp_timer_send(conn, _conn_kget_send, ECP_PTYPE_KGET, 3, 500);
+    conn->refcount = 1;
+    conn->type = ctype;
+    conn->proxy = proxy;
+    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;
+    
+    rv = conn_dhkey_new_pub_local(conn, s_idx);
+    if (!rv) rv = conn_dhkey_new_pub_remote(conn, c_idx, c_public);
+    if (!rv) rv = conn_shsec_set(conn, s_idx, c_idx, shsec);
+    if (!rv && sock->conn_create) rv = sock->conn_create(conn, payload+1, payload_size-1);
+    if (rv) {
+        ecp_conn_destroy(conn);
+        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
+        return rv;
+    }
+    if (handle_create) rv = handle_create(conn, payload+1, payload_size-1);
     if (rv) {
-        ecp_conn_unregister(conn, 0);
+        if (sock->conn_destroy) sock->conn_destroy(conn);
+        ecp_conn_destroy(conn);
+        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
         return rv;
     }
 
-    return ECP_OK;
-}
+    rv = ecp_conn_register(conn);
+    if (rv) {
+        if (handle_destroy) handle_destroy(conn);
+        if (sock->conn_destroy) sock->conn_destroy(conn);
+        ecp_conn_destroy(conn);
+        if (sock->ctx->conn_free) sock->ctx->conn_free(conn);
+        return rv;
+    }
 
-int ecp_conn_close(ECPConnection *conn, unsigned int timeout) {
-    return ecp_conn_unregister(conn, timeout);
-}
+    if (proxy) {
+#ifdef ECP_WITH_PTHREAD
+        pthread_mutex_lock(&proxy->mutex);
+#endif
+        proxy->refcount++;
+#ifdef ECP_WITH_PTHREAD
+        pthread_mutex_unlock(&proxy->mutex);
+#endif
+    }
 
-int ecp_conn_hander_init(ECPConnHandler *handler) {
-    memset(handler, 0, sizeof(ECPConnHandler));
-    return ECP_OK;
+    *_conn = conn;
+    return rv;
 }
 
-int ecp_conn_dhkey_get_curr(ECPConnection *conn, unsigned char *idx, unsigned char *public) {
-    ECPSocket *sock = conn->sock;
+ssize_t ecp_conn_handle_open(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size) {
+    if (size < 0) return size;
 
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&conn->mutex);
 #endif
+    if (!ecp_conn_is_open(conn)) conn->flags |= ECP_CONN_FLAG_OPEN;
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_unlock(&conn->mutex);
+#endif
 
-    *idx = conn->key_curr;
-    if (conn->key_curr != ECP_ECDH_IDX_INV) sock->ctx->cr.dh_pub_to_buf(public, &conn->key[conn->key_curr].public);
+    if (conn->out) {
+        return 0;
+    } else {
+        unsigned char payload[ECP_SIZE_PLD(0)];
+        unsigned char ctype = 0;
+
+        if (size < 1) return ECP_ERR;
+
+        ctype = msg[0];
+
+        ecp_pld_set_type(payload, ECP_MTYPE_OPEN);
+        ssize_t _rv = ecp_pld_send(conn, payload, sizeof(payload));
+
+        return 1;
+    }
+    return ECP_ERR;
+}
 
+ssize_t ecp_conn_handle_kget(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size) {
+    if (conn->out) {
+        ECPContext *ctx = conn->sock->ctx;
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
+        pthread_mutex_lock(&conn->mutex);
 #endif
-    
-    if (*idx == ECP_ECDH_IDX_INV) return ecp_sock_dhkey_get_curr(sock, idx, public);
-    return ECP_OK;
+        int conn_is_open = ecp_conn_is_open(conn);
+#ifdef ECP_WITH_PTHREAD
+        pthread_mutex_unlock(&conn->mutex);
+#endif
+
+        if ((size < 0) && !conn_is_open) {
+            ecp_conn_handler_msg_t *handler = ctx->handler[conn->type] ? ctx->handler[conn->type]->msg[ECP_MTYPE_OPEN] : NULL;
+            return handler ? handler(conn, mtype, msg, size) : size;
+        }
+
+        if (size < 0) return size;
+        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
+
+        int rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
+        if (!rv && !conn_is_open) {
+            ecp_conn_open_t *conn_open = ctx->handler[conn->type] ? ctx->handler[conn->type]->conn_open : NULL;
+            ssize_t _rv = conn_open(conn);
+            if (_rv < 0) rv = _rv;
+        }
+        if (rv) return rv;
+        
+        return ECP_ECDH_SIZE_KEY+1;
+    } else {
+        unsigned char payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)];
+        unsigned char *buf = ecp_pld_get_buf(payload);
+        ecp_pld_set_type(payload, ECP_MTYPE_KGET);
+
+        if (size < 0) return size;
+
+        int rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
+        if (rv) return rv;
+        
+        ssize_t _rv = ecp_pld_send(conn, payload, sizeof(payload));
+
+        return 0;
+    }
+    return ECP_ERR;
 }
-    
-static int _conn_kput_send(ECPConnection *conn, ECPTimerItem *ti) {
+ 
+ssize_t ecp_conn_handle_kput(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size) {
+    if (size < 0) return size;
+
+    if (conn->out) {
+        return 0;
+    } else {
+        unsigned char payload[ECP_SIZE_PLD(0)];
+
+        if (size < ECP_ECDH_SIZE_KEY+1) return ECP_ERR;
+
+        int rv = ecp_conn_dhkey_new_pub(conn, msg[0], msg+1);
+        if (rv) return rv;
+
+        ecp_pld_set_type(payload, ECP_MTYPE_KPUT);
+        ssize_t _rv =  ecp_pld_send(conn, payload, sizeof(payload));
+
+        return ECP_ECDH_SIZE_KEY+1;
+    }
+    return ECP_ERR;
+}
+
+static ssize_t _conn_send_kput(ECPConnection *conn, ECPTimerItem *ti) {
     unsigned char payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)];
     unsigned char *buf = ecp_pld_get_buf(payload);
-    ecp_pld_set_type(payload, ECP_PTYPE_KPUT);
-
-    int rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
+    int rv = ECP_OK;
+    
+    ecp_pld_set_type(payload, ECP_MTYPE_KPUT);
+    rv = ecp_conn_dhkey_get_curr(conn, buf, buf+1);
     if (rv) return rv;
 
-    ssize_t _rv = ecp_pld_send(conn, payload, sizeof(payload));
-    if (_rv < 0) return _rv;
-    
-    return ECP_OK;
+    return ecp_pld_send(conn, payload, sizeof(payload));
 }
 
 int ecp_conn_dhkey_new(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
     ECPDHKey new_key;
-    unsigned char key_curr;
     int rv;
+    ssize_t _rv;
     
     rv = ecp_dhkey_generate(sock->ctx, &new_key);
     if (rv) return rv;
@@ -756,9 +770,12 @@ int ecp_conn_dhkey_new(ECPConnection *conn) {
     pthread_mutex_unlock(&sock->conn.mutex);
 #endif
 
-    if (!rv) rv = ecp_timer_send(conn, _conn_kput_send, ECP_PTYPE_KPUT, 3, 500);
+    if (rv) return rv;
+    
+    _rv = ecp_timer_send(conn, _conn_send_kput, ECP_MTYPE_KPUT, 3, 500);
+    if (_rv < 0) return _rv;
         
-    return rv;
+    return ECP_OK;
 }
 
 int ecp_conn_dhkey_new_pub(ECPConnection *conn, unsigned char idx, unsigned char *public) {
@@ -782,6 +799,48 @@ int ecp_conn_dhkey_new_pub(ECPConnection *conn, unsigned char idx, unsigned char
     return rv;
 }
 
+int ecp_conn_dhkey_get_curr(ECPConnection *conn, unsigned char *idx, unsigned char *public) {
+    ECPSocket *sock = conn->sock;
+
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_lock(&conn->mutex);
+#endif
+
+    if (idx) *idx = conn->key_curr;
+    if (conn->key_curr != ECP_ECDH_IDX_INV) sock->ctx->cr.dh_pub_to_buf(public, &conn->key[conn->key_curr].public);
+
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_unlock(&conn->mutex);
+#endif
+    
+    if (*idx == ECP_ECDH_IDX_INV) return ecp_sock_dhkey_get_curr(sock, idx, public);
+    return ECP_OK;
+}
+    
+ssize_t ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size) {
+    ssize_t rv;
+
+    if (payload == NULL) return ECP_ERR;
+    if (pkt_size < ECP_SIZE_PKT_HDR) return ECP_ERR;
+    
+    // ECP_SIZE_PROTO
+    packet[0] = 0;
+    packet[1] = 0;
+    s_idx = s_idx & 0x0F;
+    c_idx = c_idx & 0x0F;
+    packet[ECP_SIZE_PROTO] = (s_idx << 4) | c_idx;
+    ctx->cr.dh_pub_to_buf(packet+ECP_SIZE_PROTO+1, public);
+    memcpy(packet+ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY, nonce, ECP_AEAD_SIZE_NONCE);
+
+    memcpy(payload, seq, ECP_SIZE_SEQ);
+    rv = ctx->cr.aead_enc(packet+ECP_SIZE_PKT_HDR, pkt_size-ECP_SIZE_PKT_HDR, payload, payload_size, shsec, nonce);
+    if (rv < 0) return ECP_ERR_ENCRYPT;
+    
+    memcpy(nonce, packet+ECP_SIZE_PKT_HDR, ECP_AEAD_SIZE_NONCE);
+        
+    return rv+ECP_SIZE_PKT_HDR;
+}
+    
 ssize_t ecp_conn_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size) {
     ecp_aead_key_t shsec;
     ecp_dh_public_t public;
@@ -825,7 +884,7 @@ ssize_t ecp_conn_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *pack
         seq[1] = (conn->seq_out & 0x00FF0000) >> 16;
         seq[2] = (conn->seq_out & 0x0000FF00) >> 8;
         seq[3] = (conn->seq_out & 0x000000FF);
-        *addr = conn->node.addr;
+        if (addr) *addr = conn->node.addr;
     }
 
 #ifdef ECP_WITH_PTHREAD
@@ -848,7 +907,28 @@ ssize_t ecp_conn_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *pack
     return _rv;
 }
 
-ssize_t ecp_pkt_handle_err(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size) {
+ssize_t ecp_proxy_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size) {
+    ECPContext *ctx = conn->sock->ctx;
+    ssize_t rv = 0;
+    
+    if (conn->proxy && ctx->pr.init) {
+        return ctx->pr.pack(conn, addr, packet, pkt_size, s_idx, c_idx, payload, payload_size);
+    } else {
+        return ecp_conn_pack(conn, addr, packet, pkt_size, s_idx, c_idx, payload, payload_size);
+    }
+}
+
+ssize_t ecp_proxy_pack_raw(ECPSocket *sock, ECPConnection *proxy, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size) {
+    ECPContext *ctx = sock->ctx;
+    
+    if (proxy && ctx->pr.init) {
+        return ctx->pr.pack_raw(proxy, addr, packet, pkt_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size);
+    } else {
+        return ecp_pack(ctx, packet, pkt_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size);
+    }
+}
+
+ssize_t ecp_pkt_handle(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *proxy, unsigned char *packet, size_t pkt_size) {
     unsigned char s_idx;
     unsigned char c_idx;
     unsigned char l_idx = ECP_ECDH_IDX_INV;
@@ -860,7 +940,6 @@ ssize_t ecp_pkt_handle_err(ECPSocket *sock, ECPNetAddr *addr, unsigned char *pac
     ECPConnection *conn = NULL;
     ECPDHKey *key = NULL;
     int rv = ECP_OK;
-    ssize_t _rv = 0;
     uint32_t c_seq, p_seq, n_seq, seq_bitmap;
     ssize_t pld_size, cnt_size, proc_size;
     
@@ -914,10 +993,9 @@ ssize_t ecp_pkt_handle_err(ECPSocket *sock, ECPNetAddr *addr, unsigned char *pac
     if (key) {
         sock->ctx->cr.dh_pub_from_buf(&public, packet+ECP_SIZE_PROTO+1);
         sock->ctx->cr.dh_shsec(&shsec, &public, &private);
+        memset(&private, 0, sizeof(private));
     }
 
-    memset(private, 0, sizeof(private));
-
     pld_size = sock->ctx->cr.aead_dec(payload, ECP_MAX_PLD, packet+ECP_SIZE_PKT_HDR, pkt_size-ECP_SIZE_PKT_HDR, &shsec, packet+ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY);
     if (pld_size < ECP_MIN_PLD) rv = ECP_ERR_DECRYPT;
     if (rv) goto pkt_handle_err;
@@ -931,20 +1009,20 @@ ssize_t ecp_pkt_handle_err(ECPSocket *sock, ECPNetAddr *addr, unsigned char *pac
     memcpy(nonce, packet+ECP_SIZE_PKT_HDR, sizeof(nonce));
 
     if (conn == NULL) {
-        if (payload[ECP_SIZE_SEQ] == ECP_PTYPE_OPEN) {
-            rv = conn_new(&conn, sock, s_idx, c_idx, packet+ECP_SIZE_PROTO+1, &shsec, payload+ECP_SIZE_PLD_HDR, pld_size-ECP_SIZE_PLD_HDR);
+        if (payload[ECP_SIZE_PLD_HDR] == ECP_MTYPE_OPEN) {
+            rv = sock->conn_new(sock, &conn, proxy, s_idx, c_idx, packet+ECP_SIZE_PROTO+1, &shsec, payload+ECP_SIZE_MSG_HDR, pld_size-ECP_SIZE_MSG_HDR);
             if (rv) return rv;
 
             seq_bitmap = 0;
             n_seq = p_seq;
-        } else if (payload[ECP_SIZE_SEQ] == ECP_PTYPE_KGET) {
-            unsigned char _payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)];
-            unsigned char *buf = ecp_pld_get_buf(_payload);
-            ecp_pld_set_type(_payload, ECP_PTYPE_KGET);
-
+        } else if (payload[ECP_SIZE_PLD_HDR] == ECP_MTYPE_KGET) {
+            unsigned char payload_[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)];
+            unsigned char *buf = ecp_pld_get_buf(payload_);
+            ecp_pld_set_type(payload_, ECP_MTYPE_KGET);
+            
             rv = ecp_sock_dhkey_get_curr(sock, buf, buf+1);
             if (!rv) {
-                ssize_t _rv = ecp_pld_send_raw(sock, addr, s_idx, c_idx, &public, &shsec, nonce, payload, _payload, sizeof(_payload));
+                ssize_t _rv = ecp_pld_send_raw(sock, proxy, addr, s_idx, c_idx, &public, &shsec, nonce, payload, payload_, sizeof(payload_));
                 if (_rv < 0) rv = _rv;
             }
             return ECP_MIN_PKT;
@@ -990,13 +1068,13 @@ ssize_t ecp_pkt_handle_err(ECPSocket *sock, ECPNetAddr *addr, unsigned char *pac
     pthread_mutex_lock(&conn->mutex);
 #endif
     memcpy(conn->nonce, nonce, sizeof(conn->nonce));
-    conn->node.addr = *addr;
+    if (addr) conn->node.addr = *addr;
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&conn->mutex);
 #endif
 
-    cnt_size = pld_size-ECP_SIZE_SEQ;
-    proc_size = ecp_pld_handle(conn, payload+pld_size-cnt_size, cnt_size);
+    cnt_size = pld_size-ECP_SIZE_PLD_HDR;
+    proc_size = ecp_msg_handle(conn, payload+pld_size-cnt_size, cnt_size);
     if (proc_size < 0) rv = ECP_ERR_HANDLE;
     if (!rv) cnt_size -= proc_size;
 
@@ -1038,7 +1116,7 @@ ssize_t ecp_pkt_send(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, s
     ssize_t rv = sock->ctx->tr.send(&sock->sock, packet, pkt_size, addr);
     if (rv < 0) return rv;
     if (rv < ECP_MIN_PKT) return ECP_ERR_SEND;
-    
+
     return rv;
 }
 
@@ -1050,44 +1128,48 @@ ssize_t ecp_pkt_recv(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, s
     return rv;
 }
 
-ssize_t ecp_pld_handle(ECPConnection *conn, unsigned char *payload, size_t payload_size) {
-    ecp_conn_handler_t *handler = NULL;
+ssize_t ecp_msg_handle(ECPConnection *conn, unsigned char *msg, size_t msg_size) {
+    ecp_conn_handler_msg_t *handler = NULL;
     ssize_t rv = 0;
-    unsigned char ptype = 0;
-    size_t rem_size = payload_size;
-    ECPSocket *sock = conn->sock;    
+    unsigned char mtype = 0;
+    size_t rem_size = msg_size;
     
     while (rem_size) {
-        ptype = payload[0];
-        payload++;
+        mtype = msg[0];
+        msg++;
         rem_size--;
 
-        if (ptype >= ECP_MAX_PTYPE) return ECP_ERR_MAX_PTYPE;
+        if (mtype >= ECP_MAX_MTYPE) return ECP_ERR_MAX_MTYPE;
         if (rem_size < ECP_MIN_MSG) return ECP_ERR_MIN_MSG;
 
-        ecp_timer_pop(conn, ptype);
-        handler = (ptype < ECP_MAX_PTYPE_SYS) && sock->handler[ptype] ? sock->handler[ptype] : (conn->handler ? conn->handler->f[ptype] : NULL);
+        ecp_timer_pop(conn, mtype);
+        handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[mtype] : NULL;
         if (handler) {
-            rv = handler(conn, ptype, payload, rem_size);
-            if (rv == 0) rv = rem_size;
+            rv = handler(conn, mtype, msg, rem_size);
             if (rv < 0) return rv;
+            if (rv == 0) rv = rem_size;
+            if (rv < ECP_MIN_MSG) rv = ECP_MIN_MSG;
             if (rv > rem_size) return ECP_ERR;
 
             rem_size -= rv;
         } else {
-            return payload_size-rem_size-1;
+            return msg_size-rem_size-1;
         }
     }
 
-    return payload_size;
+    return msg_size;
 }
 
 unsigned char *ecp_pld_get_buf(unsigned char *payload) {
-    return payload+ECP_SIZE_PLD_HDR;
+    return payload+ECP_SIZE_MSG_HDR;
 }
 
-void ecp_pld_set_type(unsigned char *payload, unsigned char ptype) {
-    payload[ECP_SIZE_SEQ] = ptype;
+void ecp_pld_set_type(unsigned char *payload, unsigned char mtype) {
+    payload[ECP_SIZE_PLD_HDR] = mtype;
+}
+
+unsigned char ecp_pld_get_type(unsigned char *payload) {
+    return payload[ECP_SIZE_PLD_HDR];
 }
 
 ssize_t ecp_pld_send(ECPConnection *conn, unsigned char *payload, size_t payload_size) {
@@ -1095,51 +1177,36 @@ ssize_t ecp_pld_send(ECPConnection *conn, unsigned char *payload, size_t payload
 }
 
 ssize_t ecp_pld_send_wkey(ECPConnection *conn, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size) {
+    unsigned char packet[ECP_MAX_PKT];
     ECPSocket *sock = conn->sock;
     ECPNetAddr addr;
-    unsigned char packet[ECP_MAX_PKT];
     ssize_t rv;
 
-    rv = ecp_conn_pack(conn, &addr, packet, ECP_MAX_PKT, s_idx, c_idx, payload, payload_size);
-    if (rv < 0) return rv;
-    
-    rv = ecp_pkt_send(sock, &addr, packet, rv);
+    rv = ecp_proxy_pack(conn, &addr, packet, ECP_MAX_PKT, s_idx, c_idx, payload, payload_size);
     if (rv < 0) return rv;
     
-    return rv-ECP_SIZE_PKT_HDR-ECP_AEAD_SIZE_TAG;
+    return ecp_pkt_send(sock, &addr, packet, rv);
 }
 
-ssize_t ecp_pld_send_raw(ECPSocket *sock, ECPNetAddr *addr, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size) {
+ssize_t ecp_pld_send_raw(ECPSocket *sock, ECPConnection *proxy, ECPNetAddr *addr, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size) {
     unsigned char packet[ECP_MAX_PKT];
+    ECPNetAddr _addr;
     ssize_t rv;
 
-    rv = ecp_pack(sock->ctx, packet, ECP_MAX_PKT, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size);
+    rv = ecp_proxy_pack_raw(sock, proxy, &_addr, packet, ECP_MAX_PKT, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size);
     if (rv < 0) return rv;
     
-    rv = ecp_pkt_send(sock, addr, packet, rv);
-    if (rv < 0) return rv;
-    
-    return rv-ECP_SIZE_PKT_HDR-ECP_AEAD_SIZE_TAG;
+    return ecp_pkt_send(sock, proxy ? &_addr : addr, packet, rv);
 }
-    
-ssize_t ecp_send(ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size) {
-    ssize_t rv;
-    
-    if (payload == NULL) {
-        unsigned char _payload[ECP_MIN_PLD];
-        ecp_pld_set_type(_payload, ptype);
-        rv = ecp_pld_send_wkey(conn, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, _payload, sizeof(_payload));
-    } else {
-        ecp_pld_set_type(payload, ptype);
-        rv = ecp_pld_send_wkey(conn, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, payload, ECP_SIZE_PLD(payload_size));
-    }
-    return rv-ECP_SIZE_PLD_HDR;
+
+ssize_t ecp_send(ECPConnection *conn, unsigned char *payload, size_t payload_size) {
+    return ecp_pld_send(conn, payload, payload_size);
 }
 
-ssize_t ecp_receive(ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size, unsigned int timeout) {
+ssize_t ecp_receive(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, unsigned int timeout) {
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&conn->mutex);
-    ssize_t rv = ecp_conn_msgq_pop(conn, ptype, payload, payload_size, timeout);
+    ssize_t rv = ecp_conn_msgq_pop(conn, mtype, msg, msg_size, timeout);
     pthread_mutex_unlock(&conn->mutex);
     return rv;
 #else
@@ -1154,7 +1221,7 @@ static int recv_p(ECPSocket *sock) {
     ssize_t rv = ecp_pkt_recv(sock, &addr, packet, ECP_MAX_PKT);
     if (rv < 0) return rv;
     
-    rv = ecp_pkt_handle(sock, &addr, packet, rv);
+    rv = ecp_pkt_handle(sock, &addr, NULL, packet, rv);
     if (rv < 0) return rv;
     
     return ECP_OK;
diff --git a/code/core.h b/code/core.h
index 09c3a2e..929461f 100644
--- a/code/core.h
+++ b/code/core.h
@@ -4,10 +4,13 @@
 #define ECP_ERR_ALLOC               -3
 
 #define ECP_ERR_MAX_SOCK_CONN       -10
-#define ECP_ERR_MAX_PTYPE           -11
-#define ECP_ERR_MAX_PLD             -12
-#define ECP_ERR_MIN_MSG             -13
-#define ECP_ERR_NET_ADDR            -14
+#define ECP_ERR_MAX_CTYPE           -11
+#define ECP_ERR_MAX_MTYPE           -12
+#define ECP_ERR_MIN_PKT             -13
+#define ECP_ERR_MAX_PLD             -14
+#define ECP_ERR_MIN_MSG             -15
+#define ECP_ERR_MAX_MSG             -16
+#define ECP_ERR_NET_ADDR            -17
 
 #define ECP_ERR_CONN_NOT_FOUND      -20
 #define ECP_ERR_ECDH_KEY_DUP        -21
@@ -31,27 +34,32 @@
 #define ECP_MAX_SOCK_KEY            8
 #define ECP_MAX_CONN_KEY            2
 #define ECP_MAX_NODE_KEY            2
-#define ECP_MAX_PTYPE               32
-#define ECP_MAX_PTYPE_SYS           4
+#define ECP_MAX_CTYPE               8
+#define ECP_MAX_MTYPE               16
 
 #define ECP_SIZE_PKT_HDR            (ECP_SIZE_PROTO+1+ECP_ECDH_SIZE_KEY+ECP_AEAD_SIZE_NONCE)
-#define ECP_SIZE_PLD_HDR            (ECP_SIZE_SEQ+1)
+#define ECP_SIZE_PLD_HDR            (ECP_SIZE_SEQ)
+#define ECP_SIZE_MSG_HDR            (ECP_SIZE_PLD_HDR+1)
 
-#define ECP_MIN_MSG                 16
 #define ECP_MAX_PKT                 1412
-#define ECP_MIN_PKT                 (ECP_SIZE_PKT_HDR+ECP_SIZE_PLD_HDR+ECP_MIN_MSG+ECP_AEAD_SIZE_TAG)
-#define ECP_MAX_PLD                 (ECP_MAX_PKT-ECP_SIZE_PKT_HDR-ECP_SIZE_PLD_HDR-ECP_AEAD_SIZE_TAG)
-#define ECP_MIN_PLD                 ECP_SIZE_PLD_HDR+ECP_MIN_MSG
+#define ECP_MAX_PLD                 (ECP_MAX_PKT-ECP_SIZE_PKT_HDR-ECP_AEAD_SIZE_TAG)
+#define ECP_MAX_MSG                 (ECP_MAX_PLD-ECP_SIZE_MSG_HDR)
+
+#define ECP_MIN_MSG                 8
+#define ECP_MIN_PLD                 (ECP_SIZE_MSG_HDR+ECP_MIN_MSG)
+#define ECP_MIN_PKT                 (ECP_SIZE_PKT_HDR+ECP_MIN_PLD+ECP_AEAD_SIZE_TAG)
 
 #define ECP_POLL_TIMEOUT            500
 #define ECP_ECDH_IDX_INV            0xFF
 #define ECP_ECDH_IDX_PERMA          0x0F
 
-#define ECP_PTYPE_OPEN              0x00
-#define ECP_PTYPE_KGET              0x01
-#define ECP_PTYPE_KPUT              0x02
+#define ECP_MTYPE_OPEN              0x00
+#define ECP_MTYPE_KGET              0x01
+#define ECP_MTYPE_KPUT              0x02
+#define ECP_MTYPE_EXEC              0x03
 
-#define ECP_SIZE_PLD(X)             (X+ECP_SIZE_PLD_HDR)
+#define ECP_SIZE_PLD(X)             ((X) < ECP_MIN_MSG ? ECP_MIN_MSG + ECP_SIZE_MSG_HDR : (X) + ECP_SIZE_MSG_HDR)
+#define ECP_SIZE_PKT(X)             ((X) < ECP_MIN_MSG ? ECP_MIN_MSG + ECP_SIZE_PKT_HDR+ECP_SIZE_MSG_HDR+ECP_AEAD_SIZE_TAG : (X) + ECP_SIZE_PKT_HDR+ECP_SIZE_MSG_HDR+ECP_AEAD_SIZE_TAG)
 
 #define ECP_CONN_FLAG_REG           0x01
 #define ECP_CONN_FLAG_OPEN          0x02
@@ -66,13 +74,16 @@ typedef long ssize_t;
 
 #ifdef ECP_WITH_PTHREAD
 #include <pthread.h>
-#include "msgq.h"
 #endif
 
 #include "posix/transport.h"
 #include "crypto/crypto.h"
 #include "timer.h"
 
+#ifdef ECP_WITH_PTHREAD
+#include "msgq.h"
+#endif
+
 #ifdef ECP_DEBUG
 #include <stdio.h>
 #define DPRINT(cnd, format, ...)    { if (cnd) { fprintf (stderr, format, __VA_ARGS__); } }
@@ -81,14 +92,19 @@ typedef long ssize_t;
 #endif
 
 struct ECPContext;
+struct ECPSocket;
 struct ECPConnection;
 
 typedef int ecp_rng_t (void *, size_t);
-typedef struct ECPConnection * ecp_conn_alloc_t (void);
-typedef void ecp_conn_free_t (struct ECPConnection *);
-typedef int ecp_conn_create_t (struct ECPConnection *, unsigned char *, size_t);
-typedef void ecp_conn_destroy_t (struct ECPConnection *);
-typedef ssize_t ecp_conn_handler_t (struct ECPConnection *, unsigned char, unsigned char *, ssize_t);
+
+typedef int ecp_conn_handler_new_t (struct ECPSocket *s, struct ECPConnection **c, struct ECPConnection *p, unsigned char s_idx, unsigned char c_idx, unsigned char *pub, ecp_aead_key_t *sh, unsigned char *msg, size_t sz);
+typedef ssize_t ecp_conn_handler_msg_t (struct ECPConnection *c, unsigned char t, unsigned char *msg, ssize_t sz);
+
+typedef struct ECPConnection * ecp_conn_alloc_t (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 struct ECPCryptoIface {
     int init;
@@ -134,6 +150,12 @@ typedef struct ECPTimeIface {
     void (*sleep_ms) (unsigned int);
 } ECPTimeIface;
 
+typedef struct ECPProxyIface {
+    int init;
+    ssize_t (*pack) (struct ECPConnection *conn, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size);
+    ssize_t (*pack_raw) (struct ECPConnection *proxy, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
+} ECPProxyIface;
+
 typedef struct ECPDHKey {
     ecp_dh_public_t public;
     ecp_dh_private_t private;
@@ -162,7 +184,10 @@ typedef struct ECPNode {
 } ECPNode;
 
 typedef struct ECPConnHandler {
-    ecp_conn_handler_t *f[ECP_MAX_PTYPE];
+    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;
 } ECPConnHandler;
 
 typedef struct ECPSockCTable {
@@ -182,6 +207,8 @@ typedef struct ECPContext {
     ECPHTableIface ht;
     ECPTransportIface tr;
     ECPTimeIface tm;
+    ECPProxyIface pr;
+    ECPConnHandler *handler[ECP_MAX_CTYPE];
 } ECPContext;
 
 typedef struct ECPSocket {
@@ -194,7 +221,7 @@ typedef struct ECPSocket {
     unsigned char key_curr;
     ECPSockCTable conn;
     ECPTimer timer;
-    ecp_conn_handler_t *handler[ECP_MAX_PTYPE_SYS];
+    ecp_conn_handler_new_t *conn_new;
     ecp_conn_create_t *conn_create;
     ecp_conn_destroy_t *conn_destroy;
 #ifdef ECP_WITH_PTHREAD
@@ -204,6 +231,7 @@ typedef struct ECPSocket {
 } ECPSocket;
 
 typedef struct ECPConnection {
+    unsigned char type;
     unsigned char out;
     unsigned char flags;
     unsigned short refcount;
@@ -220,11 +248,11 @@ typedef struct ECPConnection {
     unsigned char key_idx_map[ECP_MAX_SOCK_KEY];
     ECPDHShared shared[ECP_MAX_NODE_KEY][ECP_MAX_NODE_KEY];
     unsigned char nonce[ECP_AEAD_SIZE_NONCE];
-    ECPConnHandler *handler;
 #ifdef ECP_WITH_PTHREAD
     ECPConnMsgQ msgq;
     pthread_mutex_t mutex;
 #endif
+    struct ECPConnection *proxy;
     void *conn_data;
 } ECPConnection;
 
@@ -236,7 +264,6 @@ int ecp_time_init(ECPTimeIface *t);
 
 int ecp_dhkey_generate(ECPContext *ctx, ECPDHKey *key);
 int ecp_node_init(ECPContext *ctx, ECPNode *node, void *addr, ecp_dh_public_t *public);
-ssize_t ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
 
 int ecp_ctx_create(ECPContext *ctx);
 int ecp_ctx_destroy(ECPContext *ctx);
@@ -248,31 +275,45 @@ void ecp_sock_close(ECPSocket *sock);
 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);
+int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype);
 void ecp_conn_destroy(ECPConnection *conn);
 int ecp_conn_register(ECPConnection *conn);
-int ecp_conn_unregister(ECPConnection *conn, unsigned int timeout);
-int ecp_conn_open(ECPConnection *conn, ECPNode *node, ECPConnHandler *handler);
+void ecp_conn_unregister(ECPConnection *conn);
+
+int ecp_conn_init(ECPConnection *conn, ECPNode *node);
+int ecp_conn_open(ECPConnection *conn, ECPNode *node);
 int ecp_conn_close(ECPConnection *conn, unsigned int timeout);
-int ecp_conn_hander_init(ECPConnHandler *handler);
-int ecp_conn_dhkey_get_curr(ECPConnection *conn, unsigned char *idx, unsigned char *public);
+
+int ecp_conn_handler_init(ECPConnHandler *handler);
+ssize_t ecp_conn_send_open(ECPConnection *conn);
+int ecp_conn_handle_new(ECPSocket *sock, ECPConnection **_conn, ECPConnection *proxy, unsigned char s_idx, unsigned char c_idx, unsigned char *c_public, ecp_aead_key_t *shsec, unsigned char *payload, size_t payload_size);
+ssize_t ecp_conn_handle_open(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size);
+ssize_t ecp_conn_handle_kget(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size);
+ssize_t ecp_conn_handle_kput(ECPConnection *conn, unsigned char mtype, unsigned char *msg, ssize_t size);
+
 int ecp_conn_dhkey_new(ECPConnection *conn);
 int ecp_conn_dhkey_new_pub(ECPConnection *conn, unsigned char idx, unsigned char *public);
+int ecp_conn_dhkey_get_curr(ECPConnection *conn, unsigned char *idx, unsigned char *public);
+
+ssize_t ecp_pack(ECPContext *ctx, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
 ssize_t ecp_conn_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size);
+ssize_t ecp_proxy_pack(ECPConnection *conn, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size);
+ssize_t ecp_proxy_pack_raw(ECPSocket *sock, ECPConnection *proxy, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
 
-ssize_t ecp_pkt_handle(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size);
+ssize_t ecp_pkt_handle(ECPSocket *sock, ECPNetAddr *addr, ECPConnection *proxy, unsigned char *packet, size_t pkt_size);
 ssize_t ecp_pkt_send(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size);
 ssize_t ecp_pkt_recv(ECPSocket *sock, ECPNetAddr *addr, unsigned char *packet, size_t pkt_size);
 
-ssize_t ecp_pld_handle(ECPConnection *conn, unsigned char *payload, size_t payload_size);
+ssize_t ecp_msg_handle(ECPConnection *conn, unsigned char *msg, size_t msg_size);
 unsigned char *ecp_pld_get_buf(unsigned char *payload);
-void ecp_pld_set_type(unsigned char *payload, unsigned char ptype);
+void ecp_pld_set_type(unsigned char *payload, unsigned char mtype);
+unsigned char ecp_pld_get_type(unsigned char *payload);
 ssize_t ecp_pld_send(ECPConnection *conn, unsigned char *payload, size_t payload_size);
 ssize_t ecp_pld_send_wkey(ECPConnection *conn, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size);
-ssize_t ecp_pld_send_raw(ECPSocket *sock, ECPNetAddr *addr, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
+ssize_t ecp_pld_send_raw(ECPSocket *sock, ECPConnection *proxy, ECPNetAddr *addr, unsigned char s_idx, unsigned char c_idx, ecp_dh_public_t *public, ecp_aead_key_t *shsec, unsigned char *nonce, unsigned char *seq, unsigned char *payload, size_t payload_size);
 
-ssize_t ecp_send(ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size);
-ssize_t ecp_receive(ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size, unsigned int timeout);
+ssize_t ecp_send(ECPConnection *conn, unsigned char *payload, size_t payload_size);
+ssize_t ecp_receive(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, unsigned int timeout);
 
 int ecp_receiver(ECPSocket *sock);
 int ecp_start_receiver(ECPSocket *sock);
diff --git a/code/init.c b/code/init.c
index ba792f0..7e39f87 100644
--- a/code/init.c
+++ b/code/init.c
@@ -14,7 +14,7 @@ static int v_rng(void *buf, size_t bufsize) {
     return 0;
 }
 
-static ECPConnection *conn_alloc(void) {
+static ECPConnection *conn_alloc(unsigned char type) {
     return malloc(sizeof(ECPConnection));
 }
 
diff --git a/code/msgq.c b/code/msgq.c
index 7f32b40..53c55ea 100644
--- a/code/msgq.c
+++ b/code/msgq.c
@@ -24,7 +24,7 @@ static struct timespec *abstime_ts(struct timespec *ts, unsigned int msec) {
 int ecp_conn_msgq_create(ECPConnection *conn) {
     int i;
     
-    for (i=0; i<ECP_MAX_PTYPE; i++) {
+    for (i=0; i<ECP_MAX_MTYPE; i++) {
         int rv = pthread_cond_init(&conn->msgq.cond[i], NULL);
         if (rv) {
             int j;
@@ -42,35 +42,36 @@ int ecp_conn_msgq_create(ECPConnection *conn) {
 void ecp_conn_msgq_destroy(ECPConnection *conn) {
     int i;
     
-    for (i=0; i<ECP_MAX_PTYPE; i++) {
+    for (i=0; i<ECP_MAX_MTYPE; i++) {
         pthread_cond_destroy(&conn->msgq.cond[i]);
     }
 }
 
-ssize_t ecp_conn_msgq_push(ECPConnection *conn, unsigned char *payload, size_t payload_size) {
+ssize_t ecp_conn_msgq_push(ECPConnection *conn, unsigned char *msg, size_t msg_size) {
     ECPConnMsgQ *msgq = &conn->msgq;
     unsigned short msg_idx = msgq->empty_idx;
     unsigned short i;
     unsigned short done = 0;
-    unsigned char ptype;
+    unsigned char mtype;
     
-    if (payload_size == 0) return ECP_OK;
+    if (msg_size == 0) return ECP_OK;
 
-    ptype = *payload;
-    payload++;
-    payload_size--;
+    mtype = *msg;
+    msg++;
+    msg_size--;
 
-    if (ptype >= ECP_MAX_PTYPE) return ECP_ERR_MAX_PTYPE;
-    if (payload_size < ECP_MIN_MSG) return ECP_ERR_MIN_MSG;
+    if (mtype >= ECP_MAX_MTYPE) return ECP_ERR_MAX_MTYPE;
+    if (msg_size >= ECP_MAX_MSG) return ECP_ERR_MAX_MSG;
+    if (msg_size < ECP_MIN_MSG) return ECP_ERR_MIN_MSG;
     
     for (i=0; i<ECP_MAX_CONN_MSG; i++) {
         if (!msgq->occupied[msg_idx]) {
-            ECPMessage *msg = &msgq->msg[msg_idx];
-            if (payload_size > 0) memcpy(msg->payload, payload, payload_size);
-            msg->size = payload_size;
-            if (msgq->r_idx[ptype] == msgq->w_idx[ptype]) pthread_cond_signal(&msgq->cond[ptype]);
-            msgq->msg_idx[ptype][msgq->w_idx[ptype]] = msg_idx;
-            msgq->w_idx[ptype] = MSG_NEXT(msgq->w_idx[ptype], ECP_MAX_CONN_MSG+1);
+            ECPMessage *message = &msgq->msg[msg_idx];
+            if (msg_size > 0) memcpy(message->msg, msg, msg_size);
+            message->size = msg_size;
+            if (msgq->r_idx[mtype] == msgq->w_idx[mtype]) pthread_cond_signal(&msgq->cond[mtype]);
+            msgq->msg_idx[mtype][msgq->w_idx[mtype]] = msg_idx;
+            msgq->w_idx[mtype] = MSG_NEXT(msgq->w_idx[mtype], ECP_MAX_CONN_MSG+1);
 
             msgq->empty_idx = MSG_NEXT(msg_idx, ECP_MAX_CONN_MSG);
             msgq->occupied[msg_idx] = 1;
@@ -80,38 +81,38 @@ ssize_t ecp_conn_msgq_push(ECPConnection *conn, unsigned char *payload, size_t p
         msg_idx = MSG_NEXT(msg_idx, ECP_MAX_CONN_MSG);
     }
     if (done) {
-        return payload_size+1;
+        return msg_size+1;
     } else {
         return ECP_ERR_MAX_CONN_MSG;
     }
 }
 
-ssize_t ecp_conn_msgq_pop(ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size, unsigned int timeout) {
+ssize_t ecp_conn_msgq_pop(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, unsigned int timeout) {
     ECPConnMsgQ *msgq = &conn->msgq;
-    ECPMessage *msg;
+    ECPMessage *message;
     ssize_t rv = ECP_OK;
     unsigned short msg_idx;
 
-    if (ptype >= ECP_MAX_PTYPE) return ECP_ERR_MAX_PTYPE;
+    if (mtype >= ECP_MAX_MTYPE) return ECP_ERR_MAX_MTYPE;
 
-    if (msgq->r_idx[ptype] == msgq->w_idx[ptype]) {
+    if (msgq->r_idx[mtype] == msgq->w_idx[mtype]) {
         if (timeout == -1) {
-            pthread_cond_wait(&msgq->cond[ptype], &conn->mutex);
+            pthread_cond_wait(&msgq->cond[mtype], &conn->mutex);
         } else {
             struct timespec ts;
-            int _rv = pthread_cond_timedwait(&msgq->cond[ptype], &conn->mutex, abstime_ts(&ts, timeout));
+            int _rv = pthread_cond_timedwait(&msgq->cond[mtype], &conn->mutex, abstime_ts(&ts, timeout));
             if (_rv) rv = ECP_ERR_TIMEOUT;
         }
     }
     if (!rv) {
-        msg_idx = msgq->msg_idx[ptype][msgq->r_idx[ptype]];
-        msgq->r_idx[ptype] = MSG_NEXT(msgq->r_idx[ptype], ECP_MAX_CONN_MSG+1);
+        msg_idx = msgq->msg_idx[mtype][msgq->r_idx[mtype]];
+        msgq->r_idx[mtype] = MSG_NEXT(msgq->r_idx[mtype], ECP_MAX_CONN_MSG+1);
         msgq->occupied[msg_idx] = 0;
-        msg = &msgq->msg[msg_idx];
-        rv = msg->size;
+        message = &msgq->msg[msg_idx];
+        rv = message->size;
         if (rv >= 0) {
-            rv = MIN(payload_size, rv);
-            memcpy(payload, msg->payload, rv);
+            rv = MIN(msg_size, rv);
+            memcpy(msg, message->msg, rv);
         }
     }
     return rv;
diff --git a/code/msgq.h b/code/msgq.h
index 0bf47b3..9d16f63 100644
--- a/code/msgq.h
+++ b/code/msgq.h
@@ -9,24 +9,24 @@
 struct ECPConnection;
 
 typedef struct ECPMessage {
-    unsigned char payload[ECP_MAX_PKT];
+    unsigned char msg[ECP_MAX_MSG];
     ssize_t size;
 } ECPMessage;
 
 typedef struct ECPConnMsgQ {
     unsigned short empty_idx;
     unsigned short occupied[ECP_MAX_CONN_MSG];
-    unsigned short w_idx[ECP_MAX_PTYPE];
-    unsigned short r_idx[ECP_MAX_PTYPE];
-    unsigned short msg_idx[ECP_MAX_PTYPE][ECP_MAX_CONN_MSG+1];
+    unsigned short w_idx[ECP_MAX_MTYPE];
+    unsigned short r_idx[ECP_MAX_MTYPE];
+    unsigned short msg_idx[ECP_MAX_MTYPE][ECP_MAX_CONN_MSG+1];
     ECPMessage msg[ECP_MAX_CONN_MSG];
     pthread_mutex_t mutex;
-    pthread_cond_t cond[ECP_MAX_PTYPE];
+    pthread_cond_t cond[ECP_MAX_MTYPE];
 } ECPConnMsgQ;
 
 int ecp_conn_msgq_create(struct ECPConnection *conn);
 void ecp_conn_msgq_destroy(struct ECPConnection *conn);
-ssize_t ecp_conn_msgq_push(struct ECPConnection *conn, unsigned char *payload, size_t payload_size);
-ssize_t ecp_conn_msgq_pop(struct ECPConnection *conn, unsigned char ptype, unsigned char *payload, size_t payload_size, unsigned int timeout);
+ssize_t ecp_conn_msgq_push(struct ECPConnection *conn, unsigned char *msg, size_t msg_size);
+ssize_t ecp_conn_msgq_pop(struct ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, unsigned int timeout);
 
 #endif  /* ECP_WITH_PTHREAD */
\ No newline at end of file
diff --git a/code/test/Makefile b/code/test/Makefile
index 7992127..02ade87 100644
--- a/code/test/Makefile
+++ b/code/test/Makefile
@@ -1,6 +1,6 @@
 CFLAGS=-I.. -O3 -Wno-int-to-void-pointer-cast
 LDFLAGS=-lm -pthread
-dep=../libecpcore.a ../crypto/libecpcr.a ../htable/libecpht.a ../posix/libecptr.a ../posix/libecptm.a
+dep=../libecpcore.a ../crypto/libecpcr.a ../htable/libecpht.a ../posix/libecptr.a ../posix/libecptm.a ../init.o
 
 %.o: %.c
 	$(CC) $(CFLAGS) -c $<
diff --git a/code/test/server.c b/code/test/server.c
index a03267e..5bb36ef 100644
--- a/code/test/server.c
+++ b/code/test/server.c
@@ -17,11 +17,13 @@ ECPConnHandler handler_c;
 ECPNode node;
 ECPConnection conn;
 
-#define PTYPE_MSG       16
+#define CTYPE_TEST  0
+#define MTYPE_MSG   8
 
-ssize_t handle_open_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
+ssize_t handle_open_c(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
     uint32_t seq = 0;
     
+    ecp_conn_handle_open(conn, t, p, s);
     if (s < 0) {
         printf("OPEN ERR:%ld\n", s);
         return 0;
@@ -31,52 +33,47 @@ ssize_t handle_open_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize
     unsigned char *buf = ecp_pld_get_buf(payload);
     char *msg = "PERA JE CAR!";
 
+    ecp_pld_set_type(payload, MTYPE_MSG);
     strcpy((char *)buf, msg);
-    ssize_t _rv = ecp_send(c, PTYPE_MSG, payload, 1000);
+    ssize_t _rv = ecp_send(conn, payload, sizeof(payload));
     return 0;
 }
 
-ssize_t handle_msg_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
+ssize_t handle_msg_c(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
     printf("MSG C:%s size:%ld\n", p, s);
-    
     return s;
 }
 
-ssize_t handle_msg_s(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
+ssize_t handle_msg_s(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
     printf("MSG S:%s size:%ld\n", p, s);
 
     unsigned char payload[ECP_SIZE_PLD(1000)];
     unsigned char *buf = ecp_pld_get_buf(payload);
     char *msg = "VAISTINU JE CAR!";
 
+    ecp_pld_set_type(payload, MTYPE_MSG);
     strcpy((char *)buf, msg);
-    ssize_t _rv = ecp_send(c, PTYPE_MSG, payload, 1000);
+    ssize_t _rv = ecp_send(conn, payload, sizeof(payload));
 
     return s;
 }
 
-int conn_create(ECPConnection *c, unsigned char *p, size_t s) {
-    c->handler = &handler_s;
-    return ECP_OK;
-}
-
 int main(int argc, char *argv[]) {
     int rv;
     
     rv = ecp_init(&ctx_s);
     printf("ecp_init RV:%d\n", rv);
     
+    rv = ecp_conn_handler_init(&handler_s);
+    handler_s.msg[MTYPE_MSG] = handle_msg_s;
+    ctx_s.handler[CTYPE_TEST] = &handler_s;
+    
     rv = ecp_dhkey_generate(&ctx_s, &key_perma_s);
     printf("ecp_dhkey_generate 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_conn_hander_init(&handler_s);
-    
-    handler_s.f[PTYPE_MSG] = handle_msg_s;
-    sock_s.conn_create = conn_create;
-    
     rv = ecp_sock_open(&sock_s, "0.0.0.0:3000");
     printf("ecp_sock_open RV:%d\n", rv);
     
@@ -85,6 +82,11 @@ int main(int argc, char *argv[]) {
 
     rv = ecp_init(&ctx_c);
     printf("ecp_init RV:%d\n", rv);
+
+    rv = ecp_conn_handler_init(&handler_c);
+    handler_c.msg[ECP_MTYPE_OPEN] = handle_open_c;
+    handler_c.msg[MTYPE_MSG] = handle_msg_c;
+    ctx_c.handler[CTYPE_TEST] = &handler_c;
     
     rv = ecp_dhkey_generate(&ctx_c, &key_perma_c);
     printf("ecp_dhkey_generate RV:%d\n", rv);
@@ -101,16 +103,10 @@ int main(int argc, char *argv[]) {
     rv = ecp_node_init(&ctx_c, &node, "127.0.0.1:3000", &key_perma_s.public);
     printf("ecp_node_init RV:%d\n", rv);
 
-    rv = ecp_conn_create(&conn, &sock_c);
+    rv = ecp_conn_create(&conn, &sock_c, CTYPE_TEST);
     printf("ecp_conn_create RV:%d\n", rv);
 
-    rv = ecp_conn_hander_init(&handler_c);
-    printf("ecp_conn_hander_init RV:%d\n", rv);
-
-    handler_c.f[ECP_PTYPE_OPEN] = handle_open_c;
-    handler_c.f[PTYPE_MSG] = handle_msg_c;
-    
-    rv = ecp_conn_open(&conn, &node, &handler_c);
+    rv = ecp_conn_open(&conn, &node);
     printf("ecp_conn_open RV:%d\n", rv);
     
     while (1) sleep(1);
diff --git a/code/test/stress.c b/code/test/stress.c
index c278af1..808611e 100644
--- a/code/test/stress.c
+++ b/code/test/stress.c
@@ -16,7 +16,8 @@
 #define NUM_C       256
 #define MSG_RATE    65
 
-#define PTYPE_MSG   16
+#define CTYPE_TEST  0
+#define MTYPE_MSG   8
 
 ECPContext ctx_s;
 ECPDHKey key_perma_s;
@@ -84,7 +85,8 @@ void *sender(ECPConnection *c) {
         c->sock->ctx->rng(&rnd, sizeof(uint32_t));
         usleep(rnd % (2000000/msg_rate));
 
-        ssize_t _rv = ecp_send(c, PTYPE_MSG, payload, 1000);
+        ecp_pld_set_type(payload, MTYPE_MSG);
+        ssize_t _rv = ecp_send(c, payload, sizeof(payload));
         if (c_start && (_rv > 0)) {
             pthread_mutex_lock(&t_mtx[idx]);
             t_sent[idx]++;
@@ -93,9 +95,12 @@ void *sender(ECPConnection *c) {
     }
 }
 
-ssize_t handle_open_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
-    int idx = (int)(c->conn_data);
-    int rv = pthread_create(&s_thd[idx], NULL, (void *(*)(void *))sender, (void *)c);
+ssize_t handle_open_c(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
+    int idx = (int)(conn->conn_data);
+    int rv = 0;
+    
+    ecp_conn_handle_open(conn, t, p, s);
+    rv = pthread_create(&s_thd[idx], NULL, (void *(*)(void *))sender, (void *)conn);
     if (rv) {
         char msg[256];
         sprintf(msg, "THD %d CREATE\n", idx);
@@ -105,8 +110,8 @@ ssize_t handle_open_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize
     return 0;
 }
 
-ssize_t handle_msg_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
-    int idx = (int)(c->conn_data);
+ssize_t handle_msg_c(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
+    int idx = (int)(conn->conn_data);
     unsigned char payload[ECP_SIZE_PLD(1000)];
 
     if (c_start) {
@@ -115,21 +120,18 @@ ssize_t handle_msg_c(ECPConnection *c, unsigned char t, unsigned char *p, ssize_
         pthread_mutex_unlock(&t_mtx[idx]);
     }
     
-    // ssize_t _rv = ecp_send(c, PTYPE_MSG, payload, 1000);
+    // ecp_pld_set_type(payload, MTYPE_MSG);
+    // ssize_t _rv = ecp_send(c, payload, sizeof(payload));
     return s;
 }
 
-ssize_t handle_msg_s(ECPConnection *c, unsigned char t, unsigned char *p, ssize_t s) {
+ssize_t handle_msg_s(ECPConnection *conn, unsigned char t, unsigned char *p, ssize_t s) {
     unsigned char payload[ECP_SIZE_PLD(1000)];
-    ssize_t _rv = ecp_send(c, PTYPE_MSG, payload, 1000);
+    ecp_pld_set_type(payload, MTYPE_MSG);
+    ssize_t _rv = ecp_send(conn, payload, sizeof(payload));
     return s;
 }
 
-int conn_create(ECPConnection *c, unsigned char *p, size_t s) {
-    c->handler = &handler_s;
-    return ECP_OK;
-}
-
 int main(int argc, char *argv[]) {
     char addr[256];
     int rv;
@@ -165,14 +167,15 @@ int main(int argc, char *argv[]) {
     sigaction(SIGINFO, &actINFO, NULL);
 
     rv = ecp_init(&ctx_s);
+    if (!rv) rv = ecp_conn_handler_init(&handler_s);
+    handler_s.msg[MTYPE_MSG] = handle_msg_s;
+    ctx_s.handler[CTYPE_TEST] = &handler_s;
+
     if (!rv) rv = ecp_dhkey_generate(&ctx_s, &key_perma_s);
-    if (!rv) rv = ecp_conn_hander_init(&handler_s);
-    handler_s.f[PTYPE_MSG] = handle_msg_s;
 
     for (i=0; i<num_s; i++) {
         if (!rv) rv = ecp_sock_create(&sock_s[i], &ctx_s, &key_perma_s);
 
-        sock_s[i].conn_create = conn_create;
         strcpy(addr, "0.0.0.0:");
         sprintf(addr+strlen(addr), "%d", 3000+i);
         if (!rv) rv = ecp_sock_open(&sock_s[i], addr);
@@ -187,15 +190,17 @@ int main(int argc, char *argv[]) {
         }
     }
 
-    rv = ecp_conn_hander_init(&handler_c);
+    rv = ecp_conn_handler_init(&handler_c);
 
-    handler_c.f[ECP_PTYPE_OPEN] = handle_open_c;
-    handler_c.f[PTYPE_MSG] = handle_msg_c;
+    handler_c.msg[ECP_MTYPE_OPEN] = handle_open_c;
+    handler_c.msg[MTYPE_MSG] = handle_msg_c;
     
     for (i=0; i<num_c; i++) {
         pthread_mutex_init(&t_mtx[i], NULL);
         
         if (!rv) rv = ecp_init(&ctx_c[i]);
+        ctx_c[i].handler[CTYPE_TEST] = &handler_c;
+        
         if (!rv) rv = ecp_dhkey_generate(&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_open(&sock_c[i], NULL);
@@ -203,13 +208,13 @@ int main(int argc, char *argv[]) {
         if (!rv) rv = pthread_create(&r_thd[i], NULL, (void *(*)(void *))ecp_receiver, (void *)&sock_c[i]);
 
         strcpy(addr, "127.0.0.1:");
-        sprintf(addr+strlen(addr), "%d", 3000+(i % num_s));
+        sprintf(addr+strlen(addr), "%d", 3000 + (i % num_s));
         if (!rv) rv = ecp_node_init(&ctx_c[i], &node[i], addr, &key_perma_s.public);
         
-        if (!rv) rv = ecp_conn_create(&conn[i], &sock_c[i]);
+        if (!rv) rv = ecp_conn_create(&conn[i], &sock_c[i], CTYPE_TEST);
         conn[i].conn_data = (void *)i;
         
-        if (!rv) rv = ecp_conn_open(&conn[i], &node[i], &handler_c);
+        if (!rv) rv = ecp_conn_open(&conn[i], &node[i]);
         
         if (rv) {
             char msg[256];
diff --git a/code/timer.c b/code/timer.c
index 065a375..cf77d6e 100644
--- a/code/timer.c
+++ b/code/timer.c
@@ -19,14 +19,14 @@ void ecp_timer_destroy(ECPTimer *timer) {
 #endif
 }
 
-int ecp_timer_item_init(ECPTimerItem *ti, ECPConnection *conn, unsigned char ptype, unsigned short cnt, unsigned int timeout) {
+int ecp_timer_item_init(ECPTimerItem *ti, ECPConnection *conn, unsigned char mtype, unsigned short cnt, unsigned int timeout) {
     unsigned int abstime = conn->sock->ctx->tm.abstime_ms(timeout);
 
-    if (ptype >= ECP_MAX_PTYPE) return ECP_ERR_MAX_PTYPE;
+    if (mtype >= ECP_MAX_MTYPE) return ECP_ERR_MAX_MTYPE;
     
     ti->conn = conn;
-    ti->ptype = ptype;
-    ti->cnt = cnt;
+    ti->mtype = mtype;
+    ti->cnt = cnt-1;
     ti->timeout = timeout;
     ti->abstime = abstime;
     ti->retry = NULL;
@@ -36,8 +36,9 @@ int ecp_timer_item_init(ECPTimerItem *ti, ECPConnection *conn, unsigned char pty
     return ECP_OK;
 }
 
-int ecp_timer_push(ECPConnection *conn, ECPTimerItem *ti) {
+int ecp_timer_push(ECPTimerItem *ti) {
     int i, is_reg, rv = ECP_OK;
+    ECPConnection *conn = ti->conn;
     ECPTimer *timer = &conn->sock->timer;
 
 #ifdef ECP_WITH_PTHREAD
@@ -76,7 +77,7 @@ int ecp_timer_push(ECPConnection *conn, ECPTimerItem *ti) {
     return rv;
 }
 
-void ecp_timer_pop(ECPConnection *conn, unsigned char ptype) {
+void ecp_timer_pop(ECPConnection *conn, unsigned char mtype) {
     int i;
     ECPTimer *timer = &conn->sock->timer;
 
@@ -86,7 +87,7 @@ void ecp_timer_pop(ECPConnection *conn, unsigned char ptype) {
 
     for (i=timer->head; i>=0; i--) {
         ECPConnection *curr_conn = timer->item[i].conn;
-        if ((conn == curr_conn) && (ptype == timer->item[i].ptype)) {
+        if ((conn == curr_conn) && (mtype == timer->item[i].mtype)) {
             if (i != timer->head) {
                 memmove(timer->item+i, timer->item+i+1, sizeof(ECPTimerItem) * (timer->head-i));
                 memset(timer->item+timer->head, 0, sizeof(ECPTimerItem));
@@ -176,25 +177,25 @@ unsigned int ecp_timer_exe(ECPSocket *sock) {
         int rv = ECP_OK;
         ECPConnection *conn = to_exec[i].conn;
         ECPSocket *sock = conn->sock;
-        unsigned char ptype = to_exec[i].ptype;
+        unsigned char mtype = to_exec[i].mtype;
         unsigned char *pld = to_exec[i].pld;
         unsigned char pld_size = to_exec[i].pld_size;
         ecp_timer_retry_t *retry = to_exec[i].retry;
-        ecp_conn_handler_t *handler = (ptype < ECP_MAX_PTYPE_SYS) && sock->handler[ptype] ? sock->handler[ptype] : (conn->handler ? conn->handler->f[ptype] : NULL);
-
+        ecp_conn_handler_msg_t *handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[mtype] : NULL;
+        
         if (to_exec[i].cnt) {
             to_exec[i].cnt--;
             to_exec[i].abstime = now + to_exec[i].timeout;
             if (retry) {
                 rv = retry(conn, to_exec+i);
             } else {
-                ssize_t _rv = pld ? ecp_pld_send(conn, pld, pld_size) : ecp_send(conn, ptype, NULL, 0);
+                ssize_t _rv = ecp_pld_send(conn, pld, pld_size);
                 if (_rv < 0) rv = _rv;
             }
-            if (!rv) rv = ecp_timer_push(conn, to_exec+i);
-            if (rv && (rv != ECP_ERR_CLOSED) && handler) handler(conn, ptype, NULL, rv);
+            if (!rv) rv = ecp_timer_push(to_exec+i);
+            if (rv && (rv != ECP_ERR_CLOSED) && handler) handler(conn, mtype, NULL, rv);
         } else if (handler) {
-            handler(conn, ptype, NULL, ECP_ERR_TIMEOUT);
+            handler(conn, mtype, NULL, ECP_ERR_TIMEOUT);
         }
 #ifdef ECP_WITH_PTHREAD
         pthread_mutex_lock(&conn->mutex);
@@ -208,21 +209,16 @@ unsigned int ecp_timer_exe(ECPSocket *sock) {
     return ret;
 }
 
-int ecp_timer_send(ECPConnection *conn, ecp_timer_retry_t *send_f, unsigned char ptype, unsigned short cnt, unsigned int timeout) {
+ssize_t ecp_timer_send(ECPConnection *conn, ecp_timer_retry_t *send_f, unsigned char mtype, unsigned short cnt, unsigned int timeout) {
+    int rv = ECP_OK;
     ECPTimerItem ti;
 
-    int rv = ecp_timer_item_init(&ti, conn, ptype, cnt-1, timeout);
+    rv = ecp_timer_item_init(&ti, conn, mtype, cnt, timeout);
     if (rv) return rv;
 
     ti.retry = send_f;
-    rv = ecp_timer_push(conn, &ti);
+    rv = ecp_timer_push(&ti);
     if (rv) return rv;
 
-    ssize_t _rv = send_f(conn, NULL);
-    if (_rv < 0) {
-        ecp_timer_pop(conn, ptype);
-        return _rv;
-    }
-
-    return ECP_OK;
+    return send_f(conn, NULL);
 }
diff --git a/code/timer.h b/code/timer.h
index dd9a2a8..0d43a99 100644
--- a/code/timer.h
+++ b/code/timer.h
@@ -12,11 +12,11 @@ struct ECPConnection;
 struct ECPSocket;
 struct ECPTimerItem;
 
-typedef int ecp_timer_retry_t (struct ECPConnection *, struct ECPTimerItem *);
+typedef ssize_t ecp_timer_retry_t (struct ECPConnection *, struct ECPTimerItem *);
 
 typedef struct ECPTimerItem {
     struct ECPConnection *conn;
-    unsigned char ptype;
+    unsigned char mtype;
     unsigned short cnt;
     unsigned int abstime;
     unsigned int timeout;
@@ -35,9 +35,9 @@ typedef struct ECPTimer {
 
 int ecp_timer_create(ECPTimer *timer);
 void ecp_timer_destroy(ECPTimer *timer);
-int ecp_timer_item_init(ECPTimerItem *ti, struct ECPConnection *conn, unsigned char ptype, unsigned short cnt, unsigned int timeout);
-int ecp_timer_push(struct ECPConnection *conn, ECPTimerItem *ti);
-void ecp_timer_pop(struct ECPConnection *conn, unsigned char ptype);
+int ecp_timer_item_init(ECPTimerItem *ti, struct ECPConnection *conn, unsigned char mtype, unsigned short cnt, unsigned int timeout);
+int ecp_timer_push(ECPTimerItem *ti);
+void ecp_timer_pop(struct ECPConnection *conn, unsigned char mtype);
 void ecp_timer_remove(struct ECPConnection *conn);
 unsigned int ecp_timer_exe(struct ECPSocket *sock);
-int ecp_timer_send(struct ECPConnection *conn, ecp_timer_retry_t *send_f, unsigned char ptype, unsigned short cnt, unsigned int timeout);
\ No newline at end of file
+ssize_t ecp_timer_send(struct ECPConnection *conn, ecp_timer_retry_t *send_f, unsigned char mtype, unsigned short cnt, unsigned int timeout);
\ No newline at end of file
-- 
cgit v1.2.3