From d830d95720e41b3374dd1edda04ef1ea4272967d Mon Sep 17 00:00:00 2001 From: Uros Majstorovic Date: Sun, 13 Aug 2017 00:22:37 +0200 Subject: proxy renamed to vconn --- code/build.sh | 2 +- code/proxy/Makefile | 13 -- code/proxy/proxy.c | 533 ------------------------------------------------- code/proxy/proxy.h | 22 -- code/test/Makefile | 20 +- code/test/init_proxy.c | 42 ---- code/test/init_vconn.c | 42 ++++ code/test/pr_client.c | 91 --------- code/test/pr_server.c | 80 -------- code/test/proxy.c | 54 ----- code/test/vc_client.c | 91 +++++++++ code/test/vc_server.c | 80 ++++++++ code/test/vcs.c | 54 +++++ code/vconn/Makefile | 13 ++ code/vconn/vconn.c | 533 +++++++++++++++++++++++++++++++++++++++++++++++++ code/vconn/vconn.h | 22 ++ 16 files changed, 846 insertions(+), 846 deletions(-) delete mode 100644 code/proxy/Makefile delete mode 100644 code/proxy/proxy.c delete mode 100644 code/proxy/proxy.h delete mode 100644 code/test/init_proxy.c create mode 100644 code/test/init_vconn.c delete mode 100644 code/test/pr_client.c delete mode 100644 code/test/pr_server.c delete mode 100644 code/test/proxy.c create mode 100644 code/test/vc_client.c create mode 100644 code/test/vc_server.c create mode 100644 code/test/vcs.c create mode 100644 code/vconn/Makefile create mode 100644 code/vconn/vconn.c create mode 100644 code/vconn/vconn.h diff --git a/code/build.sh b/code/build.sh index 96f26e3..ce29ff5 100755 --- a/code/build.sh +++ b/code/build.sh @@ -1,6 +1,6 @@ #!/bin/sh -subdirs="core proxy util test" +subdirs="core vconn util test" for i in $subdirs; do (cd $i && make $1 && cd ..) || exit; diff --git a/code/proxy/Makefile b/code/proxy/Makefile deleted file mode 100644 index 9a8490c..0000000 --- a/code/proxy/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -CFLAGS = -I../core -pthread -O3 $(PIC) - -obj = proxy.o - - -%.o: %.c %.h - $(CC) $(CFLAGS) -c $< - -all: $(obj) - $(AR) rcs libecpproxy.a $(obj) - -clean: - rm -f *.o *.a \ No newline at end of file diff --git a/code/proxy/proxy.c b/code/proxy/proxy.c deleted file mode 100644 index a981a2f..0000000 --- a/code/proxy/proxy.c +++ /dev/null @@ -1,533 +0,0 @@ -#include "core.h" -#include "proxy.h" - -#include - -#ifdef ECP_WITH_PTHREAD -static pthread_mutex_t key_perma_mutex; -static pthread_mutex_t key_next_mutex; -#endif - -static void *key_perma_table; -static void *key_next_table; - -static unsigned char key_null[ECP_ECDH_SIZE_KEY] = { 0 }; - -static ECPConnHandler handler_f; -static ECPConnHandler handler_b; - -static int proxyf_create(ECPConnection *conn, unsigned char *payload, size_t size) { - ECPContext *ctx = conn->sock->ctx; - ECPConnProxyF *conn_p = (ECPConnProxyF *)conn; - int rv = ECP_OK; - - if (conn->out) return ECP_ERR; - if (conn->type != ECP_CTYPE_PROXYF) return ECP_ERR; - if (size < 2*ECP_ECDH_SIZE_KEY) return ECP_ERR; - - conn_p->key_next_curr = 0; - memset(conn_p->key_next, 0, sizeof(conn_p->key_next)); - memset(conn_p->key_out, 0, sizeof(conn_p->key_out)); - memcpy(conn_p->key_next[conn_p->key_next_curr], payload, ECP_ECDH_SIZE_KEY); - memcpy(conn_p->key_out, payload+ECP_ECDH_SIZE_KEY, ECP_ECDH_SIZE_KEY); - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_next_mutex); -#endif -#ifdef ECP_WITH_HTABLE - rv = ctx->ht.init ? ctx->ht.insert(key_next_table, conn_p->key_next[conn_p->key_next_curr], conn) : ECP_ERR; -#endif -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&key_next_mutex); -#endif - - return rv; -} - -static void proxyf_destroy(ECPConnection *conn) { - ECPContext *ctx = conn->sock->ctx; - ECPConnProxyF *conn_p = (ECPConnProxyF *)conn; - - if (conn->out) return; - if (conn->type != ECP_CTYPE_PROXYF) return; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_next_mutex); - pthread_mutex_lock(&conn->mutex); -#endif -#ifdef ECP_WITH_HTABLE - if (ctx->ht.init) { - int i; - for (i=0; ikey_next[i], key_null, ECP_ECDH_SIZE_KEY)) ctx->ht.remove(key_next_table, conn_p->key_next[i]); - } - } -#endif -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&conn->mutex); - pthread_mutex_unlock(&key_next_mutex); -#endif -} - -static ssize_t _proxyf_send_open(ECPConnection *conn) { - ECPConnProxy *conn_p = (ECPConnProxy *)conn; - ECPConnection *conn_next = conn_p->next; - unsigned char payload[ECP_SIZE_PLD(0)]; - - if (conn_next == NULL) return ECP_ERR; - - ecp_pld_set_type(payload, ECP_MTYPE_KGET_REQ); - return ecp_pld_send_wkey(conn_next, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, payload, sizeof(payload)); -} - -static ssize_t _proxyf_retry_kget(ECPConnection *conn, ECPTimerItem *ti) { - if (conn->parent == NULL) return ECP_ERR; - - return _proxyf_send_open(conn->parent); -} - -static ssize_t proxyf_open(ECPConnection *conn) { - int rv = ECP_OK; - ECPTimerItem ti; - ECPConnProxy *conn_p = (ECPConnProxy *)conn; - ECPConnection *conn_next = conn_p->next; - - rv = ecp_timer_item_init(&ti, conn_next, ECP_MTYPE_KGET_REP, 3, 3000); - if (rv) return rv; - - ti.retry = _proxyf_retry_kget; - rv = ecp_timer_push(&ti); - if (rv) return rv; - - return _proxyf_send_open(conn); -} - -static ssize_t proxyf_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { - if (conn->type != ECP_CTYPE_PROXYF) return ECP_ERR; - - if (mtype & ECP_MTYPE_FLAG_REP) { - if (!conn->out) return ECP_ERR; - if (size < 0) { - ecp_conn_handler_msg_t *handler = NULL; - while (conn->type == ECP_CTYPE_PROXYF) { - ECPConnProxy *conn_p = (ECPConnProxy *)conn; - conn = conn_p->next; - } - handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[ECP_MTYPE_OPEN] : NULL; - return handler ? handler(conn, seq, mtype, msg, size) : size; - } - - return ecp_conn_handle_open(conn, seq, mtype, msg, size); - } else { - ECPContext *ctx = conn->sock->ctx; - ECPConnProxyF *conn_p = (ECPConnProxyF *)conn; - int rv = ECP_OK; - unsigned char ctype = 0; - - if (conn->out) return ECP_ERR; - if (size < 0) return size; - if (size < 1+2*ECP_ECDH_SIZE_KEY) return ECP_ERR; - -#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_p->key_next[conn_p->key_next_curr], msg, ECP_ECDH_SIZE_KEY)) { - conn_p->key_next_curr = (conn_p->key_next_curr + 1) % ECP_MAX_NODE_KEY; -#ifdef ECP_WITH_HTABLE - if (ctx->ht.init) { - if (memcmp(conn_p->key_next[conn_p->key_next_curr], key_null, ECP_ECDH_SIZE_KEY)) ctx->ht.remove(key_next_table, conn_p->key_next[conn_p->key_next_curr]); - rv = ctx->ht.insert(key_next_table, conn_p->key_next[conn_p->key_next_curr], conn); - } else { - rv = ECP_ERR; - } -#endif - if (!rv) memcpy(conn_p->key_next[conn_p->key_next_curr], msg, ECP_ECDH_SIZE_KEY); - } - -#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; - } - - return ECP_ERR; -} - -static ssize_t proxyf_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { - ECPContext *ctx = conn->sock->ctx; - ECPConnection *conn_out = NULL; - ECPConnProxyF *conn_p = (ECPConnProxyF *)conn; - unsigned char *payload = NULL; - ssize_t rv; - - if (conn->out) return ECP_ERR; - if (conn->type != ECP_CTYPE_PROXYF) return ECP_ERR; - - if (size < 0) return size; - if (size < ECP_MIN_PKT) return ECP_ERR_MIN_PKT; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_perma_mutex); -#endif -#ifdef ECP_WITH_HTABLE - conn_out = ctx->ht.init ? ctx->ht.search(key_perma_table, conn_p->key_out) : NULL; -#endif - 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 - } -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&key_perma_mutex); -#endif - - if (conn_out == NULL) return ECP_ERR; - - payload = msg - ECP_SIZE_MSG_HDR; - ecp_pld_set_type(payload, ECP_MTYPE_EXEC); - rv = ecp_pld_send(conn_out, payload, ECP_SIZE_MSG_HDR+size); - -#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 - - if (rv < 0) return rv; - return size; -} - -static int proxyb_insert(ECPConnection *conn) { - int rv = ECP_OK; - ECPContext *ctx = conn->sock->ctx; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_perma_mutex); -#endif -#ifdef ECP_WITH_HTABLE - rv = ctx->ht.init ? ctx->ht.insert(key_perma_table, ctx->cr.dh_pub_get_buf(&conn->node.public), conn) : ECP_OK; -#endif -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&key_perma_mutex); -#endif - - return rv; -} - -static void proxyb_remove(ECPConnection *conn) { - ECPContext *ctx = conn->sock->ctx; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_perma_mutex); -#endif -#ifdef ECP_WITH_HTABLE - if (ctx->ht.init) ctx->ht.remove(key_perma_table, ctx->cr.dh_pub_get_buf(&conn->node.public)); -#endif -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&key_perma_mutex); -#endif -} - -static int proxyb_create(ECPConnection *conn, unsigned char *payload, size_t size) { - ECPContext *ctx = conn->sock->ctx; - - if (conn->out) return ECP_ERR; - if (conn->type != ECP_CTYPE_PROXYB) return ECP_ERR; - - // XXX should verify perma_key - if (size < ECP_ECDH_SIZE_KEY) return ECP_ERR; - ctx->cr.dh_pub_from_buf(&conn->node.public, payload); - - return proxyb_insert(conn); -} - -static void proxyb_destroy(ECPConnection *conn) { - ECPContext *ctx = conn->sock->ctx; - - if (conn->out) return; - if (conn->type != ECP_CTYPE_PROXYB) return; - - proxyb_remove(conn); -} - -static ssize_t _proxyb_send_open(ECPConnection *conn, ECPTimerItem *ti) { - ECPSocket *sock = conn->sock; - ECPContext *ctx = sock->ctx; - unsigned char payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)]; - unsigned char *buf = ecp_pld_get_buf(payload); - int rv = ECP_OK; - - // XXX server should verify perma_key - ecp_pld_set_type(payload, ECP_MTYPE_OPEN_REQ); - buf[0] = conn->type; - memcpy(buf+1, ctx->cr.dh_pub_get_buf(&sock->key_perma.public), ECP_ECDH_SIZE_KEY); - - return ecp_pld_send(conn, payload, sizeof(payload)); -} - -static ssize_t proxyb_open(ECPConnection *conn) { - return ecp_timer_send(conn, _proxyb_send_open, ECP_MTYPE_OPEN_REP, 3, 500); -} - -static void proxyb_close(ECPConnection *conn) { - proxyb_remove(conn); -} - -static ssize_t proxyb_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { - ssize_t rv; - int is_open; - - if (conn->type != ECP_CTYPE_PROXYB) 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 - - rv = ecp_conn_handle_open(conn, seq, mtype, msg, size); - if (rv < 0) return rv; - - if (mtype & ECP_MTYPE_FLAG_REP) { - if (!conn->out) return ECP_ERR; - if (!is_open) { - int rv = proxyb_insert(conn); - if (rv) return rv; - } - return rv; - } else { - if (conn->out) return ECP_ERR; - if (size < rv+ECP_ECDH_SIZE_KEY) return ECP_ERR; - - msg += rv; - - // XXX should verify perma_key - return rv+ECP_ECDH_SIZE_KEY; - } - - return ECP_ERR; -} - -static ssize_t proxyb_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { - ECPContext *ctx = conn->sock->ctx; - unsigned char *payload = NULL; - ssize_t rv; - - if (conn->type != ECP_CTYPE_PROXYB) return ECP_ERR; - - if (size < 0) return size; - if (size < ECP_MIN_PKT) return ECP_ERR_MIN_PKT; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&key_next_mutex); -#endif -#ifdef ECP_WITH_HTABLE - conn = ctx->ht.init ? ctx->ht.search(key_next_table, msg+ECP_SIZE_PROTO+1) : NULL; -#endif - if (conn) { -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&conn->mutex); -#endif - conn->refcount++; -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&conn->mutex); -#endif - } -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&key_next_mutex); -#endif - - if (conn == NULL) return ECP_ERR; - - payload = msg - ECP_SIZE_MSG_HDR; - ecp_pld_set_type(payload, ECP_MTYPE_EXEC); - rv = ecp_pld_send(conn, payload, ECP_SIZE_MSG_HDR+size); - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_lock(&conn->mutex); -#endif - conn->refcount--; -#ifdef ECP_WITH_PTHREAD - pthread_mutex_unlock(&conn->mutex); -#endif - - if (rv < 0) return rv; - return size; -} - -static ssize_t proxy_set_msg(ECPConnection *conn, unsigned char *pld_out, size_t pld_out_size, unsigned char *pld_in, size_t pld_in_size) { - if ((conn->type == ECP_CTYPE_PROXYF) && conn->out) { - unsigned char mtype = ecp_pld_get_type(pld_in); - if ((mtype == ECP_MTYPE_OPEN_REQ) || (mtype == ECP_MTYPE_KGET_REQ)) { - ECPConnProxy *conn_p = (ECPConnProxy *)conn; - ECPContext *ctx = conn->sock->ctx; - ECPConnection *conn_next = conn_p->next; - unsigned char *buf = NULL; - int rv; - - if (pld_out_size < ECP_SIZE_MSG_HDR+2+2*ECP_ECDH_SIZE_KEY) return ECP_ERR; - if (conn_next == NULL) return ECP_ERR; - - ecp_pld_set_type(pld_out, ECP_MTYPE_OPEN_REQ); - buf = ecp_pld_get_buf(pld_out); - - buf[0] = ECP_CTYPE_PROXYF; - rv = ecp_conn_dhkey_get_curr(conn_next, NULL, buf+1); - if (rv) return rv; - - memcpy(buf+1+ECP_ECDH_SIZE_KEY, ctx->cr.dh_pub_get_buf(&conn_next->node.public), ECP_ECDH_SIZE_KEY); - buf[1+2*ECP_ECDH_SIZE_KEY] = ECP_MTYPE_RELAY; - - return ECP_SIZE_MSG_HDR+2+2*ECP_ECDH_SIZE_KEY; - } - } - - ecp_pld_set_type(pld_out, ECP_MTYPE_RELAY); - return ECP_SIZE_MSG_HDR; -} - - -static ssize_t proxy_pack(ECPConnection *conn, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size, ECPNetAddr *addr, ecp_seq_t *seq, int *rbuf_idx) { - ECPContext *ctx = conn->sock->ctx; - - if (conn->parent) { - unsigned char payload_[ECP_MAX_PLD]; - ssize_t rv, hdr_size = proxy_set_msg(conn->parent, payload_, sizeof(payload_), payload, payload_size); - if (hdr_size < 0) return hdr_size; - - rv = ecp_conn_pack(conn, payload_+hdr_size, ECP_MAX_PLD-hdr_size, s_idx, c_idx, payload, payload_size, NULL, seq, rbuf_idx); - if (rv < 0) return rv; - - return proxy_pack(conn->parent, packet, pkt_size, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, payload_, rv+hdr_size, addr, NULL, NULL); - } else { - return ecp_conn_pack(conn, packet, pkt_size, s_idx, c_idx, payload, payload_size, addr, seq, rbuf_idx); - } -} - -static ssize_t proxy_pack_raw(ECPSocket *sock, ECPConnection *parent, 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, ecp_seq_t seq, unsigned char *payload, size_t payload_size, ECPNetAddr *addr) { - ECPContext *ctx = sock->ctx; - - if (parent) { - unsigned char payload_[ECP_MAX_PLD]; - ssize_t rv, hdr_size = proxy_set_msg(parent, payload_, sizeof(payload_), payload, payload_size); - if (hdr_size < 0) return hdr_size; - - rv = ecp_pack(ctx, payload_+hdr_size, ECP_MAX_PLD-hdr_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size); - if (rv < 0) return rv; - - return proxy_pack(parent, packet, pkt_size, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, payload_, rv+hdr_size, addr, NULL, NULL); - } else { - return ecp_pack(ctx, packet, pkt_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size); - } -} - -int ecp_proxy_init(ECPContext *ctx) { - int rv; - - rv = ecp_conn_handler_init(&handler_f); - if (rv) return rv; - - handler_f.conn_create = proxyf_create; - handler_f.conn_destroy = proxyf_destroy; - handler_f.conn_open = proxyf_open; - handler_f.msg[ECP_MTYPE_OPEN] = proxyf_handle_open; - handler_f.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec; - handler_f.msg[ECP_MTYPE_RELAY] = proxyf_handle_relay; - ctx->handler[ECP_CTYPE_PROXYF] = &handler_f; - - rv = ecp_conn_handler_init(&handler_b); - if (rv) return rv; - - handler_b.conn_create = proxyb_create; - handler_b.conn_destroy = proxyb_destroy; - handler_b.conn_open = proxyb_open; - handler_b.conn_close = proxyb_close; - handler_b.msg[ECP_MTYPE_OPEN] = proxyb_handle_open; - handler_b.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec; - handler_b.msg[ECP_MTYPE_RELAY] = proxyb_handle_relay; - ctx->handler[ECP_CTYPE_PROXYB] = &handler_b; - - ctx->pack = proxy_pack; - ctx->pack_raw = proxy_pack_raw; - -#ifdef ECP_WITH_PTHREAD - pthread_mutex_init(&key_perma_mutex, NULL); - pthread_mutex_init(&key_next_mutex, NULL); -#endif - -#ifdef ECP_WITH_HTABLE - if (ctx->ht.init) { - key_perma_table = ctx->ht.create(ctx); - key_next_table = ctx->ht.create(ctx); - } -#endif - - return ECP_OK; -} - -int ecp_conn_proxy_init(ECPConnection *conn, ECPNode *conn_node, ECPConnProxy proxy[], ECPNode proxy_node[], int size) { - ECPSocket *sock = conn->sock; - int i, rv; - - rv = ecp_conn_init(conn, conn_node); - if (rv) return rv; - - conn->parent = (ECPConnection *)&proxy[size-1]; - for (i=0; i -#include -#include - -#include "core.h" -#include "proxy.h" - -static int v_rng(void *buf, size_t bufsize) { - int fd; - - if((fd = open("/dev/urandom", O_RDONLY)) < 0) return -1; - size_t nb = read(fd, buf, bufsize); - close(fd); - if (nb != bufsize) return -1; - return 0; -} - -static ECPConnection *conn_alloc(unsigned char type) { - switch (type) { - case ECP_CTYPE_PROXYF: - return malloc(sizeof(ECPConnProxyF)); - default: - return malloc(sizeof(ECPConnection)); - } -} - -static void conn_free(ECPConnection *conn) { - free(conn); -} - -int ecp_init(ECPContext *ctx) { - int rv; - - rv = ecp_ctx_create(ctx); - if (rv) return rv; - - ctx->rng = v_rng; - ctx->conn_alloc = conn_alloc; - ctx->conn_free = conn_free; - - return ecp_proxy_init(ctx); -} \ No newline at end of file diff --git a/code/test/init_vconn.c b/code/test/init_vconn.c new file mode 100644 index 0000000..2e82598 --- /dev/null +++ b/code/test/init_vconn.c @@ -0,0 +1,42 @@ +#include +#include +#include + +#include "core.h" +#include "vconn.h" + +static int v_rng(void *buf, size_t bufsize) { + int fd; + + if((fd = open("/dev/urandom", O_RDONLY)) < 0) return -1; + size_t nb = read(fd, buf, bufsize); + close(fd); + if (nb != bufsize) return -1; + return 0; +} + +static ECPConnection *conn_alloc(unsigned char type) { + switch (type) { + case ECP_CTYPE_VCONN: + return malloc(sizeof(ECPVConnIn)); + default: + return malloc(sizeof(ECPConnection)); + } +} + +static void conn_free(ECPConnection *conn) { + free(conn); +} + +int ecp_init(ECPContext *ctx) { + int rv; + + rv = ecp_ctx_create(ctx); + if (rv) return rv; + + ctx->rng = v_rng; + ctx->conn_alloc = conn_alloc; + ctx->conn_free = conn_free; + + return ecp_ctx_vconn_init(ctx); +} \ No newline at end of file diff --git a/code/test/pr_client.c b/code/test/pr_client.c deleted file mode 100644 index d643dd3..0000000 --- a/code/test/pr_client.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include -#include -#include - -#include "core.h" -#include "proxy.h" -#include "util.h" - -ECPContext ctx; -ECPSocket sock; -ECPConnHandler handler; - -ECPConnection conn; -ECPNode node; - -ECPConnProxy conn_proxy[20]; -ECPNode node_proxy[20]; - -#define CTYPE_TEST 0 -#define MTYPE_MSG 8 - -ssize_t handle_open(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { - uint32_t seq = 0; - - ecp_conn_handle_open(conn, sq, t, p, s); - if (s < 0) { - printf("OPEN ERR:%ld\n", s); - return s; - } - - printf("OPEN!\n"); - - unsigned char payload[ECP_SIZE_PLD(1000)]; - 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(conn, payload, sizeof(payload)); - return s; -} - -ssize_t handle_msg(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { - printf("MSG S:%s size:%ld\n", p, s); - return s; -} - -static void usage(char *arg) { - fprintf(stderr, "Usage: %s ... \n", arg); - exit(1); -} - -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_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[1]); - printf("ecp_util_node_load RV:%d\n", rv); - - for (i=0; i -#include -#include -#include - -#include "core.h" -#include "proxy.h" -#include "util.h" - -ECPContext ctx; -ECPSocket sock; -ECPDHKey key_perma; -ECPConnHandler handler; - -ECPNode node; -ECPConnection conn; - -#define CTYPE_TEST 0 -#define MTYPE_MSG 8 - -ssize_t handle_open(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { - printf("OPEN RECEIVED\n"); - return ecp_conn_handle_open(conn, sq, t, p, s); -} - -ssize_t handle_msg(ECPConnection *conn, ecp_seq_t sq, 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(conn, payload, sizeof(payload)); - - return s; -} - -static void usage(char *arg) { - fprintf(stderr, "Usage: %s \n", arg); - exit(1); -} - -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_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_PROXYB); - printf("ecp_conn_create RV:%d\n", rv); - - rv = ecp_conn_open(&conn, &node); - printf("ecp_conn_open RV:%d\n", rv); - - while (1) sleep(1); -} \ No newline at end of file diff --git a/code/test/proxy.c b/code/test/proxy.c deleted file mode 100644 index ae7cce5..0000000 --- a/code/test/proxy.c +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include -#include - -#include "core.h" -#include "util.h" -#include "proxy.h" - -ECPContext ctx; -ECPSocket sock; -ECPDHKey key_perma; - -ECPNode node; -ECPConnection conn; - -static void usage(char *arg) { - fprintf(stderr, "Usage: %s
[node.pub]\n", arg); - exit(1); -} - -int main(int argc, char *argv[]) { - int rv; - - if ((argc < 3) || (argc > 4)) usage(argv[0]); - - rv = ecp_init(&ctx); - printf("ecp_init RV:%d\n", rv); - - 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_open(&sock, argv[1]); - printf("ecp_sock_open RV:%d\n", rv); - - rv = ecp_start_receiver(&sock); - printf("ecp_start_receiver RV:%d\n", rv); - - if (argc == 4) { - 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_PROXYB); - printf("ecp_conn_create RV:%d\n", rv); - - rv = ecp_conn_open(&conn, &node); - printf("ecp_conn_open RV:%d\n", rv); - } - - while (1) sleep(1); -} \ No newline at end of file diff --git a/code/test/vc_client.c b/code/test/vc_client.c new file mode 100644 index 0000000..586fec5 --- /dev/null +++ b/code/test/vc_client.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +#include "core.h" +#include "vconn.h" +#include "util.h" + +ECPContext ctx; +ECPSocket sock; +ECPConnHandler handler; + +ECPConnection conn; +ECPNode node; + +ECPVConnection vconn[20]; +ECPNode vconn_node[20]; + +#define CTYPE_TEST 0 +#define MTYPE_MSG 8 + +ssize_t handle_open(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { + uint32_t seq = 0; + + ecp_conn_handle_open(conn, sq, t, p, s); + if (s < 0) { + printf("OPEN ERR:%ld\n", s); + return s; + } + + printf("OPEN!\n"); + + unsigned char payload[ECP_SIZE_PLD(1000)]; + 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(conn, payload, sizeof(payload)); + return s; +} + +ssize_t handle_msg(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { + printf("MSG S:%s size:%ld\n", p, s); + return s; +} + +static void usage(char *arg) { + fprintf(stderr, "Usage: %s ... \n", arg); + exit(1); +} + +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_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[1]); + printf("ecp_util_node_load RV:%d\n", rv); + + for (i=0; i +#include +#include +#include + +#include "core.h" +#include "vconn.h" +#include "util.h" + +ECPContext ctx; +ECPSocket sock; +ECPDHKey key_perma; +ECPConnHandler handler; + +ECPNode node; +ECPConnection conn; + +#define CTYPE_TEST 0 +#define MTYPE_MSG 8 + +ssize_t handle_open(ECPConnection *conn, ecp_seq_t sq, unsigned char t, unsigned char *p, ssize_t s) { + printf("OPEN RECEIVED\n"); + return ecp_conn_handle_open(conn, sq, t, p, s); +} + +ssize_t handle_msg(ECPConnection *conn, ecp_seq_t sq, 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(conn, payload, sizeof(payload)); + + return s; +} + +static void usage(char *arg) { + fprintf(stderr, "Usage: %s \n", arg); + exit(1); +} + +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_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_open(&conn, &node); + printf("ecp_conn_open RV:%d\n", rv); + + while (1) sleep(1); +} \ No newline at end of file diff --git a/code/test/vcs.c b/code/test/vcs.c new file mode 100644 index 0000000..1dbf67d --- /dev/null +++ b/code/test/vcs.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include + +#include "core.h" +#include "util.h" +#include "vconn.h" + +ECPContext ctx; +ECPSocket sock; +ECPDHKey key_perma; + +ECPNode node; +ECPConnection conn; + +static void usage(char *arg) { + fprintf(stderr, "Usage: %s
[node.pub]\n", arg); + exit(1); +} + +int main(int argc, char *argv[]) { + int rv; + + if ((argc < 3) || (argc > 4)) usage(argv[0]); + + rv = ecp_init(&ctx); + printf("ecp_init RV:%d\n", rv); + + 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_open(&sock, argv[1]); + printf("ecp_sock_open RV:%d\n", rv); + + rv = ecp_start_receiver(&sock); + printf("ecp_start_receiver RV:%d\n", rv); + + if (argc == 4) { + 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_open(&conn, &node); + printf("ecp_conn_open RV:%d\n", rv); + } + + while (1) sleep(1); +} \ No newline at end of file diff --git a/code/vconn/Makefile b/code/vconn/Makefile new file mode 100644 index 0000000..0292b0d --- /dev/null +++ b/code/vconn/Makefile @@ -0,0 +1,13 @@ +CFLAGS = -I../core -pthread -O3 $(PIC) + +obj = vconn.o + + +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + +all: $(obj) + $(AR) rcs libecpvconn.a $(obj) + +clean: + rm -f *.o *.a \ No newline at end of file diff --git a/code/vconn/vconn.c b/code/vconn/vconn.c new file mode 100644 index 0000000..97ced70 --- /dev/null +++ b/code/vconn/vconn.c @@ -0,0 +1,533 @@ +#include "core.h" +#include "vconn.h" + +#include + +#ifdef ECP_WITH_PTHREAD +static pthread_mutex_t key_perma_mutex; +static pthread_mutex_t key_next_mutex; +#endif + +static void *key_perma_table; +static void *key_next_table; + +static unsigned char key_null[ECP_ECDH_SIZE_KEY] = { 0 }; + +static ECPConnHandler handler_f; +static ECPConnHandler handler_b; + +static int vconn_create(ECPConnection *conn, unsigned char *payload, size_t size) { + ECPContext *ctx = conn->sock->ctx; + ECPVConnIn *conn_v = (ECPVConnIn *)conn; + int rv = ECP_OK; + + 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 +#ifdef ECP_WITH_HTABLE + rv = ctx->ht.init ? ctx->ht.insert(key_next_table, conn_v->key_next[conn_v->key_next_curr], conn) : ECP_ERR; +#endif +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&key_next_mutex); +#endif + + return rv; +} + +static void vconn_destroy(ECPConnection *conn) { + ECPContext *ctx = conn->sock->ctx; + ECPVConnIn *conn_v = (ECPVConnIn *)conn; + + if (conn->out) return; + if (conn->type != ECP_CTYPE_VCONN) return; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&key_next_mutex); + pthread_mutex_lock(&conn->mutex); +#endif +#ifdef ECP_WITH_HTABLE + if (ctx->ht.init) { + int i; + for (i=0; ikey_next[i], key_null, ECP_ECDH_SIZE_KEY)) ctx->ht.remove(key_next_table, conn_v->key_next[i]); + } + } +#endif +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&conn->mutex); + pthread_mutex_unlock(&key_next_mutex); +#endif +} + +static ssize_t _vconn_send_open(ECPConnection *conn) { + ECPVConnection *conn_v = (ECPVConnection *)conn; + ECPConnection *conn_next = conn_v->next; + unsigned char payload[ECP_SIZE_PLD(0)]; + + if (conn_next == NULL) return ECP_ERR; + + ecp_pld_set_type(payload, ECP_MTYPE_KGET_REQ); + return ecp_pld_send_wkey(conn_next, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, payload, sizeof(payload)); +} + +static ssize_t _vconn_retry_kget(ECPConnection *conn, ECPTimerItem *ti) { + if (conn->parent == NULL) return ECP_ERR; + + return _vconn_send_open(conn->parent); +} + +static ssize_t vconn_open(ECPConnection *conn) { + int rv = ECP_OK; + ECPTimerItem ti; + ECPVConnection *conn_v = (ECPVConnection *)conn; + ECPConnection *conn_next = conn_v->next; + + rv = ecp_timer_item_init(&ti, conn_next, ECP_MTYPE_KGET_REP, 3, 3000); + if (rv) return rv; + + ti.retry = _vconn_retry_kget; + rv = ecp_timer_push(&ti); + if (rv) return rv; + + return _vconn_send_open(conn); +} + +static ssize_t vconn_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { + if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR; + + if (mtype & ECP_MTYPE_FLAG_REP) { + if (!conn->out) return ECP_ERR; + if (size < 0) { + ecp_conn_handler_msg_t *handler = NULL; + while (conn->type == ECP_CTYPE_VCONN) { + ECPVConnection *conn_v = (ECPVConnection *)conn; + conn = conn_v->next; + } + handler = conn->sock->ctx->handler[conn->type] ? conn->sock->ctx->handler[conn->type]->msg[ECP_MTYPE_OPEN] : NULL; + return handler ? handler(conn, seq, mtype, msg, size) : size; + } + + return ecp_conn_handle_open(conn, seq, mtype, msg, size); + } else { + ECPContext *ctx = conn->sock->ctx; + ECPVConnIn *conn_v = (ECPVConnIn *)conn; + int rv = ECP_OK; + unsigned char ctype = 0; + + if (conn->out) return ECP_ERR; + if (size < 0) return size; + if (size < 1+2*ECP_ECDH_SIZE_KEY) return ECP_ERR; + +#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)) { + conn_v->key_next_curr = (conn_v->key_next_curr + 1) % ECP_MAX_NODE_KEY; +#ifdef ECP_WITH_HTABLE + if (ctx->ht.init) { + if (memcmp(conn_v->key_next[conn_v->key_next_curr], key_null, ECP_ECDH_SIZE_KEY)) ctx->ht.remove(key_next_table, conn_v->key_next[conn_v->key_next_curr]); + rv = ctx->ht.insert(key_next_table, conn_v->key_next[conn_v->key_next_curr], conn); + } else { + rv = ECP_ERR; + } +#endif + if (!rv) memcpy(conn_v->key_next[conn_v->key_next_curr], msg, ECP_ECDH_SIZE_KEY); + } + +#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; + } + + return ECP_ERR; +} + +static ssize_t vconn_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { + ECPContext *ctx = conn->sock->ctx; + ECPConnection *conn_out = NULL; + ECPVConnIn *conn_v = (ECPVConnIn *)conn; + unsigned char *payload = NULL; + ssize_t rv; + + if (conn->out) return ECP_ERR; + if (conn->type != ECP_CTYPE_VCONN) return ECP_ERR; + + if (size < 0) return size; + if (size < ECP_MIN_PKT) return ECP_ERR_MIN_PKT; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&key_perma_mutex); +#endif +#ifdef ECP_WITH_HTABLE + conn_out = ctx->ht.init ? ctx->ht.search(key_perma_table, conn_v->key_out) : NULL; +#endif + 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 + } +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&key_perma_mutex); +#endif + + if (conn_out == NULL) return ECP_ERR; + + payload = msg - ECP_SIZE_MSG_HDR; + ecp_pld_set_type(payload, ECP_MTYPE_EXEC); + rv = ecp_pld_send(conn_out, payload, ECP_SIZE_MSG_HDR+size); + +#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 + + if (rv < 0) return rv; + return size; +} + +static int vlink_insert(ECPConnection *conn) { + int rv = ECP_OK; + ECPContext *ctx = conn->sock->ctx; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&key_perma_mutex); +#endif +#ifdef ECP_WITH_HTABLE + rv = ctx->ht.init ? ctx->ht.insert(key_perma_table, ctx->cr.dh_pub_get_buf(&conn->node.public), conn) : ECP_OK; +#endif +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&key_perma_mutex); +#endif + + return rv; +} + +static void vlink_remove(ECPConnection *conn) { + ECPContext *ctx = conn->sock->ctx; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&key_perma_mutex); +#endif +#ifdef ECP_WITH_HTABLE + if (ctx->ht.init) ctx->ht.remove(key_perma_table, ctx->cr.dh_pub_get_buf(&conn->node.public)); +#endif +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&key_perma_mutex); +#endif +} + +static int vlink_create(ECPConnection *conn, unsigned char *payload, size_t size) { + ECPContext *ctx = conn->sock->ctx; + + 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; + ctx->cr.dh_pub_from_buf(&conn->node.public, payload); + + return vlink_insert(conn); +} + +static void vlink_destroy(ECPConnection *conn) { + ECPContext *ctx = conn->sock->ctx; + + if (conn->out) return; + if (conn->type != ECP_CTYPE_VLINK) return; + + vlink_remove(conn); +} + +static ssize_t _vlink_send_open(ECPConnection *conn, ECPTimerItem *ti) { + ECPSocket *sock = conn->sock; + ECPContext *ctx = sock->ctx; + unsigned char payload[ECP_SIZE_PLD(ECP_ECDH_SIZE_KEY+1)]; + unsigned char *buf = ecp_pld_get_buf(payload); + int rv = ECP_OK; + + // XXX server should verify perma_key + ecp_pld_set_type(payload, ECP_MTYPE_OPEN_REQ); + buf[0] = conn->type; + memcpy(buf+1, ctx->cr.dh_pub_get_buf(&sock->key_perma.public), ECP_ECDH_SIZE_KEY); + + return ecp_pld_send(conn, payload, sizeof(payload)); +} + +static ssize_t vlink_open(ECPConnection *conn) { + return ecp_timer_send(conn, _vlink_send_open, ECP_MTYPE_OPEN_REP, 3, 500); +} + +static void vlink_close(ECPConnection *conn) { + vlink_remove(conn); +} + +static ssize_t vlink_handle_open(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { + ssize_t 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 + + rv = ecp_conn_handle_open(conn, seq, mtype, msg, size); + if (rv < 0) return rv; + + if (mtype & ECP_MTYPE_FLAG_REP) { + if (!conn->out) return ECP_ERR; + if (!is_open) { + int rv = vlink_insert(conn); + if (rv) return rv; + } + return rv; + } else { + if (conn->out) return ECP_ERR; + if (size < rv+ECP_ECDH_SIZE_KEY) return ECP_ERR; + + msg += rv; + + // XXX should verify perma_key + return rv+ECP_ECDH_SIZE_KEY; + } + + return ECP_ERR; +} + +static ssize_t vlink_handle_relay(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, ssize_t size) { + ECPContext *ctx = conn->sock->ctx; + unsigned char *payload = NULL; + ssize_t rv; + + if (conn->type != ECP_CTYPE_VLINK) return ECP_ERR; + + if (size < 0) return size; + if (size < ECP_MIN_PKT) return ECP_ERR_MIN_PKT; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&key_next_mutex); +#endif +#ifdef ECP_WITH_HTABLE + conn = ctx->ht.init ? ctx->ht.search(key_next_table, msg+ECP_SIZE_PROTO+1) : NULL; +#endif + if (conn) { +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&conn->mutex); +#endif + conn->refcount++; +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&conn->mutex); +#endif + } +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&key_next_mutex); +#endif + + if (conn == NULL) return ECP_ERR; + + payload = msg - ECP_SIZE_MSG_HDR; + ecp_pld_set_type(payload, ECP_MTYPE_EXEC); + rv = ecp_pld_send(conn, payload, ECP_SIZE_MSG_HDR+size); + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_lock(&conn->mutex); +#endif + conn->refcount--; +#ifdef ECP_WITH_PTHREAD + pthread_mutex_unlock(&conn->mutex); +#endif + + if (rv < 0) return rv; + return size; +} + +static ssize_t vconn_set_msg(ECPConnection *conn, unsigned char *pld_out, size_t pld_out_size, unsigned char *pld_in, size_t pld_in_size) { + if ((conn->type == ECP_CTYPE_VCONN) && conn->out) { + unsigned char mtype = ecp_pld_get_type(pld_in); + if ((mtype == ECP_MTYPE_OPEN_REQ) || (mtype == ECP_MTYPE_KGET_REQ)) { + ECPVConnection *conn_v = (ECPVConnection *)conn; + ECPContext *ctx = conn->sock->ctx; + ECPConnection *conn_next = conn_v->next; + unsigned char *buf = NULL; + int rv; + + if (pld_out_size < ECP_SIZE_MSG_HDR+2+2*ECP_ECDH_SIZE_KEY) return ECP_ERR; + if (conn_next == NULL) return ECP_ERR; + + ecp_pld_set_type(pld_out, ECP_MTYPE_OPEN_REQ); + buf = ecp_pld_get_buf(pld_out); + + buf[0] = ECP_CTYPE_VCONN; + rv = ecp_conn_dhkey_get_curr(conn_next, NULL, buf+1); + if (rv) return rv; + + memcpy(buf+1+ECP_ECDH_SIZE_KEY, ctx->cr.dh_pub_get_buf(&conn_next->node.public), ECP_ECDH_SIZE_KEY); + buf[1+2*ECP_ECDH_SIZE_KEY] = ECP_MTYPE_RELAY; + + return ECP_SIZE_MSG_HDR+2+2*ECP_ECDH_SIZE_KEY; + } + } + + ecp_pld_set_type(pld_out, ECP_MTYPE_RELAY); + return ECP_SIZE_MSG_HDR; +} + + +static ssize_t vconn_pack(ECPConnection *conn, unsigned char *packet, size_t pkt_size, unsigned char s_idx, unsigned char c_idx, unsigned char *payload, size_t payload_size, ECPNetAddr *addr, ecp_seq_t *seq, int *rbuf_idx) { + ECPContext *ctx = conn->sock->ctx; + + if (conn->parent) { + unsigned char payload_[ECP_MAX_PLD]; + ssize_t rv, hdr_size = vconn_set_msg(conn->parent, payload_, sizeof(payload_), payload, payload_size); + if (hdr_size < 0) return hdr_size; + + rv = ecp_conn_pack(conn, payload_+hdr_size, ECP_MAX_PLD-hdr_size, s_idx, c_idx, payload, payload_size, NULL, seq, rbuf_idx); + if (rv < 0) return rv; + + return vconn_pack(conn->parent, packet, pkt_size, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, payload_, rv+hdr_size, addr, NULL, NULL); + } else { + return ecp_conn_pack(conn, packet, pkt_size, s_idx, c_idx, payload, payload_size, addr, seq, rbuf_idx); + } +} + +static ssize_t vconn_pack_raw(ECPSocket *sock, ECPConnection *parent, 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, ecp_seq_t seq, unsigned char *payload, size_t payload_size, ECPNetAddr *addr) { + ECPContext *ctx = sock->ctx; + + if (parent) { + unsigned char payload_[ECP_MAX_PLD]; + ssize_t rv, hdr_size = vconn_set_msg(parent, payload_, sizeof(payload_), payload, payload_size); + if (hdr_size < 0) return hdr_size; + + rv = ecp_pack(ctx, payload_+hdr_size, ECP_MAX_PLD-hdr_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size); + if (rv < 0) return rv; + + return vconn_pack(parent, packet, pkt_size, ECP_ECDH_IDX_INV, ECP_ECDH_IDX_INV, payload_, rv+hdr_size, addr, NULL, NULL); + } else { + return ecp_pack(ctx, packet, pkt_size, s_idx, c_idx, public, shsec, nonce, seq, payload, payload_size); + } +} + +int ecp_ctx_vconn_init(ECPContext *ctx) { + int rv; + + rv = ecp_conn_handler_init(&handler_f); + if (rv) return rv; + + handler_f.conn_create = vconn_create; + handler_f.conn_destroy = vconn_destroy; + handler_f.conn_open = vconn_open; + handler_f.msg[ECP_MTYPE_OPEN] = vconn_handle_open; + handler_f.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec; + handler_f.msg[ECP_MTYPE_RELAY] = vconn_handle_relay; + ctx->handler[ECP_CTYPE_VCONN] = &handler_f; + + rv = ecp_conn_handler_init(&handler_b); + if (rv) return rv; + + handler_b.conn_create = vlink_create; + handler_b.conn_destroy = vlink_destroy; + handler_b.conn_open = vlink_open; + handler_b.conn_close = vlink_close; + handler_b.msg[ECP_MTYPE_OPEN] = vlink_handle_open; + handler_b.msg[ECP_MTYPE_EXEC] = ecp_conn_handle_exec; + handler_b.msg[ECP_MTYPE_RELAY] = vlink_handle_relay; + ctx->handler[ECP_CTYPE_VLINK] = &handler_b; + + ctx->pack = vconn_pack; + ctx->pack_raw = vconn_pack_raw; + +#ifdef ECP_WITH_PTHREAD + pthread_mutex_init(&key_perma_mutex, NULL); + pthread_mutex_init(&key_next_mutex, NULL); +#endif + +#ifdef ECP_WITH_HTABLE + if (ctx->ht.init) { + key_perma_table = ctx->ht.create(ctx); + key_next_table = ctx->ht.create(ctx); + } +#endif + + return ECP_OK; +} + +int ecp_vconn_init(ECPConnection *conn, ECPNode *conn_node, ECPVConnection vconn[], ECPNode vconn_node[], int size) { + ECPSocket *sock = conn->sock; + int i, rv; + + rv = ecp_conn_init(conn, conn_node); + if (rv) return rv; + + conn->parent = (ECPConnection *)&vconn[size-1]; + for (i=0; i