summaryrefslogtreecommitdiff
path: root/ecp/src/ecp/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'ecp/src/ecp/core.c')
-rw-r--r--ecp/src/ecp/core.c963
1 files changed, 559 insertions, 404 deletions
diff --git a/ecp/src/ecp/core.c b/ecp/src/ecp/core.c
index 3d4342d..9585388 100644
--- a/ecp/src/ecp/core.c
+++ b/ecp/src/ecp/core.c
@@ -12,10 +12,6 @@
#include "vconn/vconn.h"
#endif
-#ifdef ECP_WITH_DIR
-#include "dir/dir.h"
-#endif
-
#include "cr.h"
#include "tr.h"
#include "tm.h"
@@ -34,13 +30,12 @@ int ecp_dhkey_gen(ECPDHKey *key) {
return ECP_OK;
}
-int ecp_ctx_init(ECPContext *ctx, ecp_err_handler_t handle_err, ecp_dir_handler_t handle_dir, ecp_conn_alloc_t conn_alloc, ecp_conn_free_t conn_free) {
+int ecp_ctx_init(ECPContext *ctx, ecp_err_handler_t handle_err, ecp_conn_new_t conn_new, ecp_conn_free_t conn_free) {
int rv;
memset(ctx, 0, sizeof(ECPContext));
ctx->handle_err = handle_err;
- ctx->handle_dir = handle_dir;
- ctx->conn_alloc = conn_alloc;
+ ctx->conn_new = conn_new;
ctx->conn_free = conn_free;
rv = ecp_tr_init(ctx);
@@ -52,14 +47,44 @@ int ecp_ctx_init(ECPContext *ctx, ecp_err_handler_t handle_err, ecp_dir_handler_
return ECP_OK;
}
-int ecp_ctx_set_handler(ECPContext *ctx, ECPConnHandler *handler, unsigned char ctype) {
- if (ctype >= ECP_MAX_CTYPE) return ECP_ERR_CTYPE;
+int ecp_ctx_set_handler(ECPContext *ctx, unsigned char ctype, ECPConnHandler *handler) {
+ unsigned char _ctype = ctype & ECP_CTYPE_MASK;
- ctx->handler[ctype] = handler;
+ if (ctype & ECP_CTYPE_FLAG_SYS) {
+ if (_ctype >= ECP_MAX_CTYPE_SYS) return ECP_ERR_CTYPE;
+ ctx->handler_sys[_ctype] = handler;
+ } else {
+ if (_ctype >= ECP_MAX_CTYPE) return ECP_ERR_CTYPE;
+ ctx->handler[_ctype] = handler;
+ }
return ECP_OK;
}
-int ecp_node_init(ECPNode *node, ecp_ecdh_public_t *public, void *addr) {
+ECPConnHandler *ecp_ctx_get_handler(ECPContext *ctx, unsigned char ctype) {
+ unsigned char _ctype = ctype & ECP_CTYPE_MASK;
+
+ if (ctype & ECP_CTYPE_FLAG_SYS) {
+ if (_ctype >= ECP_MAX_CTYPE_SYS) return NULL;
+ return ctx->handler_sys[_ctype];
+ } else {
+ if (_ctype >= ECP_MAX_CTYPE) return NULL;
+ return ctx->handler[_ctype];
+ }
+ return NULL;
+}
+
+int ecp_addr_init(ecp_tr_addr_t *addr, void *addr_s) {
+ int rv = ECP_OK;
+
+ memset(addr, 0, sizeof(ecp_tr_addr_t));
+ if (addr_s) {
+ rv = ecp_tr_addr_set(addr, addr_s);
+ }
+
+ return rv;
+}
+
+void ecp_node_init(ECPNode *node, ecp_ecdh_public_t *public, ecp_tr_addr_t *addr) {
memset(node, 0, sizeof(ECPNode));
if (public) {
@@ -70,13 +95,8 @@ int ecp_node_init(ECPNode *node, ecp_ecdh_public_t *public, void *addr) {
}
if (addr) {
- int rv;
-
- rv = ecp_tr_addr_set(&node->addr, addr);
- if (rv) return ECP_ERR_NET_ADDR;
+ node->addr = *addr;
}
-
- return ECP_OK;
}
void ecp_node_set_pub(ECPNode *node, ecp_ecdh_public_t *public) {
@@ -106,7 +126,7 @@ static int conn_table_create(ECPConnTable *conn_table) {
return ECP_ERR;
}
- rv = pthread_mutex_init(&conn_table->mutex_inb, NULL);
+ rv = pthread_mutex_init(&conn_table->mutex_gc, NULL);
if (rv) {
pthread_mutex_destroy(&conn_table->mutex);
return ECP_ERR;
@@ -120,8 +140,8 @@ static int conn_table_create(ECPConnTable *conn_table) {
if (conn_table->keys == NULL) rv = ECP_ERR_ALLOC;
if (!rv) {
- conn_table->keys_inb = ecp_ht_create_keys();
- if (conn_table->keys_inb == NULL) rv = ECP_ERR_ALLOC;
+ conn_table->keys_gc = ecp_ht_create_keys();
+ if (conn_table->keys_gc == NULL) rv = ECP_ERR_ALLOC;
}
if (!rv) {
@@ -131,11 +151,11 @@ static int conn_table_create(ECPConnTable *conn_table) {
if (rv) {
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_destroy(&conn_table->mutex_inb);
+ pthread_mutex_destroy(&conn_table->mutex_gc);
pthread_mutex_destroy(&conn_table->mutex);
#endif
if (conn_table->addrs) ecp_ht_destroy(conn_table->addrs);
- if (conn_table->keys_inb) ecp_ht_destroy(conn_table->keys_inb);
+ if (conn_table->keys_gc) ecp_ht_destroy(conn_table->keys_gc);
if (conn_table->keys) ecp_ht_destroy(conn_table->keys);
}
#endif
@@ -145,12 +165,12 @@ static int conn_table_create(ECPConnTable *conn_table) {
static void conn_table_destroy(ECPConnTable *conn_table) {
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_destroy(&conn_table->mutex_inb);
+ pthread_mutex_destroy(&conn_table->mutex_gc);
pthread_mutex_destroy(&conn_table->mutex);
#endif
#ifdef ECP_WITH_HTABLE
ecp_ht_destroy(conn_table->addrs);
- ecp_ht_destroy(conn_table->keys_inb);
+ ecp_ht_destroy(conn_table->keys_gc);
ecp_ht_destroy(conn_table->keys);
#endif
}
@@ -162,7 +182,7 @@ static int conn_table_insert(ECPConnection *conn) {
int i, rv = ECP_OK;
if (ecp_conn_is_outb(conn)) {
- if (ecp_conn_is_root(conn) && !ecp_conn_is_open(conn)) {
+ if (ecp_conn_is_root(conn) && !_ecp_conn_is_open(conn)) {
rv = ecp_ht_insert(sock->conn_table.addrs, &conn->remote.addr, conn);
if (rv) return rv;
}
@@ -178,8 +198,8 @@ static int conn_table_insert(ECPConnection *conn) {
ecp_ht_remove(sock->conn_table.keys, &conn->key[j].public);
}
}
- if (ecp_conn_is_root(conn) && !ecp_conn_is_open(conn)) {
- ecp_ht_remove(sock->conn_table.addrs, &conn->remote.addr);
+ if (ecp_conn_is_root(conn) && !_ecp_conn_is_open(conn)) {
+ ecp_ht_remove_kv(sock->conn_table.addrs, &conn->remote.addr, conn);
}
return rv;
}
@@ -214,16 +234,12 @@ static int conn_table_insert(ECPConnection *conn) {
return ECP_OK;
}
-static int conn_table_insert_inb(ECPConnection *conn) {
+static int conn_table_insert_gc(ECPConnection *conn) {
ECPSocket *sock = conn->sock;
int rv = ECP_OK;
#ifdef ECP_WITH_HTABLE
- unsigned char idx;
-
- idx = conn->rkey_curr % ECP_MAX_NODE_KEY;
-
- rv = ecp_ht_insert(sock->conn_table.keys_inb, &conn->rkey[idx].public, conn);
+ rv = ecp_ht_insert(sock->conn_table.keys_gc, &conn->remote.key_perma.public, conn);
#endif
return rv;
@@ -241,8 +257,8 @@ static void conn_table_remove(ECPConnection *conn) {
ecp_ht_remove(sock->conn_table.keys, &conn->key[i].public);
}
}
- if (ecp_conn_is_root(conn) && !ecp_conn_is_open(conn)) {
- ecp_ht_remove(sock->conn_table.addrs, &conn->remote.addr);
+ if (ecp_conn_is_root(conn) && !_ecp_conn_is_open(conn)) {
+ ecp_ht_remove_kv(sock->conn_table.addrs, &conn->remote.addr, conn);
}
} else {
for (i=0; i<ECP_MAX_NODE_KEY; i++) {
@@ -273,126 +289,168 @@ static void conn_table_remove_addr(ECPConnection *conn) {
ECPSocket *sock = conn->sock;
#ifdef ECP_WITH_HTABLE
- ecp_ht_remove(sock->conn_table.addrs, &conn->remote.addr);
+ ecp_ht_remove_kv(sock->conn_table.addrs, &conn->remote.addr, conn);
#endif
}
-static ECPConnection *conn_table_search(ECPSocket *sock, unsigned char c_idx, ecp_ecdh_public_t *c_public, ecp_tr_addr_t *addr, ECPConnection *parent) {
-#ifdef ECP_WITH_VCONN
- if ((c_public == NULL) && parent) {
- return parent->next;
- }
-#endif
-
+static ECPConnection *conn_table_search_pub(ECPSocket *sock, unsigned char c_idx, ecp_ecdh_public_t *c_public) {
#ifdef ECP_WITH_HTABLE
+ return ecp_ht_search(sock->conn_table.keys, c_public);
+#else /* ECP_WITH_HTABLE */
+ ECPConnection *conn = NULL;
+ int i;
- if (c_public) {
- return ecp_ht_search(sock->conn_table.keys, c_public);
- } else if (addr) {
- return ecp_ht_search(sock->conn_table.addrs, addr);
- } else {
- return NULL;
+ for (i=0; i<sock->conn_table.size; i++) {
+ conn = sock->conn_table.arr[i];
+ if (ecp_conn_is_outb(conn)) {
+ if (c_idx >= ECP_MAX_CONN_KEY) continue;
+
+ if (conn->key[c_idx].valid && ecp_ecdh_pub_eq(c_public, &conn->key[c_idx].public)) {
+ return conn;
+ }
+ } else {
+ unsigned char _c_idx;
+
+ if (c_idx & ~ECP_ECDH_IDX_MASK) continue;
+
+ _c_idx = c_idx % ECP_MAX_NODE_KEY;
+ if (conn->rkey[_c_idx].valid && ecp_ecdh_pub_eq(c_public, &conn->rkey[_c_idx].public)) {
+ return conn;
+ }
+ }
}
+ return NULL;
+#endif /* ECP_WITH_HTABLE */
+}
+static ECPConnection *conn_table_search_addr(ECPSocket *sock, ecp_tr_addr_t *addr) {
+#ifdef ECP_WITH_HTABLE
+ return ecp_ht_search(sock->conn_table.addrs, addr);
#else /* ECP_WITH_HTABLE */
ECPConnection *conn = NULL;
int i;
- if (c_public) {
- for (i=0; i<sock->conn_table.size; i++) {
- conn = sock->conn_table.arr[i];
- if (ecp_conn_is_outb(conn)) {
- if (c_idx >= ECP_MAX_CONN_KEY) continue;
+ for (i=0; i<sock->conn_table.size; i++) {
+ conn = sock->conn_table.arr[i];
+ if (ecp_conn_is_root(conn) && ecp_conn_is_outb(conn) && ecp_tr_addr_eq(&conn->remote.addr, addr)) {
+ return conn;
+ }
+ }
- if (conn->key[c_idx].valid && ecp_ecdh_pub_eq(c_public, &conn->key[c_idx].public)) {
- return conn;
- }
- } else {
- unsigned char _c_idx;
+ return NULL;
+#endif /* ECP_WITH_HTABLE */
+}
- if (c_idx & ~ECP_ECDH_IDX_MASK) continue;
+static ECPConnection *conn_table_search_addr_next(ECPSocket *sock, ecp_tr_addr_t *addr, ECPConnection *_conn) {
+#ifdef ECP_WITH_HTABLE
+ return ecp_ht_search_next(sock->conn_table.addrs, addr, _conn);
+#else /* ECP_WITH_HTABLE */
+ ECPConnection *conn = NULL;
+ int i, f;
- _c_idx = c_idx % ECP_MAX_NODE_KEY;
- if (conn->rkey[_c_idx].valid && ecp_ecdh_pub_eq(c_public, &conn->rkey[_c_idx].public)) {
- return conn;
- }
- }
- }
- } else if (addr) {
- for (i=0; i<sock->conn_table.size; i++) {
- conn = sock->conn_table.arr[i];
+ f = 0;
+ for (i=0; i<sock->conn_table.size; i++) {
+ conn = sock->conn_table.arr[i];
+ if (f)
if (ecp_conn_is_root(conn) && ecp_conn_is_outb(conn) && ecp_tr_addr_eq(&conn->remote.addr, addr)) {
return conn;
}
+ } else if (conn == _conn) {
+ f = 1;
}
}
return NULL;
-
#endif /* ECP_WITH_HTABLE */
}
-static void conn_table_expire_inb(ECPSocket *sock, ecp_sts_t to) {
+static ECPConnection *conn_table_search(ECPSocket *sock, unsigned char c_idx, ecp_ecdh_public_t *c_public, ecp_tr_addr_t *addr, ECPConnection *parent) {
+#ifdef ECP_WITH_VCONN
+ if ((c_public == NULL) && parent) {
+ if ((parent->type == ECP_CTYPE_VCONN) && ecp_conn_is_outb(parent)) {
+ ECPVConnOutb *_parent = (ECPVConnOutb *)parent;
+
+ return _parent->next;
+ }
+ return NULL;
+ }
+#endif
+
+ if (c_public) {
+ return conn_table_search_pub(sock, c_idx, c_public);
+ } else if (addr) {
+ return conn_table_search_addr(sock, addr);
+ }
+
+ return NULL;
+}
+
+static void conn_table_expire(ECPSocket *sock, ecp_sts_t to, ecp_conn_expired_t conn_expired) {
ECPConnection *conn;
ECPConnection *to_remove[ECP_MAX_EXP];
- int i, remove_cnt;
- ecp_sts_t access_ts, now = ecp_tm_get_tick();
+ int i, remove_cnt, expired;
+ ecp_sts_t now = ecp_tm_get_s();
#ifdef ECP_WITH_HTABLE
struct hashtable_itr itr;
void *remove_next;
int rv = ECP_OK;
+
remove_next = NULL;
do {
+ ecp_ht_table_t *keys_gc = sock->conn_table.keys_gc;
remove_cnt = 0;
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_lock(&sock->conn_table.mutex_inb);
+ pthread_mutex_lock(&sock->conn_table.mutex_gc);
#endif
- ecp_ht_itr_create(&itr, sock->conn_table.keys_inb);
- if (remove_next) {
- ecp_ht_itr_search(&itr, remove_next);
- remove_next = NULL;
- }
- do {
- conn = ecp_ht_itr_value(&itr);
- if (conn) {
+ if (ecp_ht_count(keys_gc) > 0) {
+ ecp_ht_itr_create(&itr, keys_gc);
+ if (remove_next) {
+ ecp_ht_itr_search(&itr, remove_next);
+ remove_next = NULL;
+ }
+ do {
+ conn = ecp_ht_itr_value(&itr);
+
#ifdef ECP_WITH_PTHREAD
pthread_mutex_lock(&conn->mutex);
#endif
- access_ts = conn->access_ts;
+ expired = conn_expired(conn, now, to);
#ifdef ECP_WITH_PTHREAD
pthread_mutex_unlock(&conn->mutex);
#endif
- if (now - access_ts > to) {
+ if (expired) {
+ rv = ecp_ht_itr_remove(&itr);
+
to_remove[remove_cnt] = conn;
remove_cnt++;
- rv = ecp_ht_itr_remove(&itr);
if (remove_cnt == ECP_MAX_EXP) {
- if (!rv) remove_next = ecp_ht_itr_key(&itr);
+ if (!rv) {
+ remove_next = ecp_ht_itr_key(&itr);
+ } else {
+ remove_next = NULL;
+ }
break;
}
} else {
rv = ecp_ht_itr_advance(&itr);
}
- } else {
- rv = ECP_ITR_END;
- }
- } while (rv == ECP_OK);
+ } while (rv == ECP_OK);
+ }
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_unlock(&sock->conn_table.mutex_inb);
+ pthread_mutex_unlock(&sock->conn_table.mutex_gc);
#endif
for (i=0; i<remove_cnt; i++) {
_ecp_conn_close(to_remove[i]);
}
-
} while (remove_next);
#else /* ECP_WITH_HTABLE */
@@ -406,18 +464,18 @@ static void conn_table_expire_inb(ECPSocket *sock, ecp_sts_t to) {
for (i=0; i<sock->conn_table.size; i++) {
conn = sock->conn_table.arr[i];
- if (ecp_conn_is_inb(conn)) {
+ if (ecp_conn_is_gc(conn)) {
#ifdef ECP_WITH_PTHREAD
pthread_mutex_lock(&conn->mutex);
#endif
- access_ts = conn->access_ts;
+ expired = conn_expired(conn, now, to);
#ifdef ECP_WITH_PTHREAD
pthread_mutex_unlock(&conn->mutex);
#endif
- if (now - access_ts > to) {
+ if (expired) {
to_remove[remove_cnt] = conn;
remove_cnt++;
if (remove_cnt == ECP_MAX_EXP) break;
@@ -492,7 +550,7 @@ void ecp_sock_destroy(ECPSocket *sock) {
#endif
}
-int ecp_sock_open(ECPSocket *sock, void *myaddr) {
+int ecp_sock_open(ECPSocket *sock, ecp_tr_addr_t *myaddr) {
return ecp_tr_open(sock, myaddr);
}
@@ -606,11 +664,20 @@ void ecp_sock_get_nonce(ECPSocket *sock, ecp_nonce_t *nonce) {
#endif
}
+static int _conn_expired_inb(ECPConnection *conn, ecp_sts_t now, ecp_sts_t to) {
+ if (ecp_conn_is_inb(conn) && _ecp_conn_expired(conn, now, to)) return 1;
+ return 0;
+}
+
+void ecp_sock_expire(ECPSocket *sock, ecp_sts_t to, ecp_conn_expired_t conn_expired) {
+ conn_table_expire(sock, to, conn_expired);
+}
+
int ecp_sock_expire_inb(ECPSocket *sock, ecp_sts_t to) {
int rv;
rv = ecp_sock_minkey_new(sock);
- if (!rv) conn_table_expire_inb(sock, to);
+ if (!rv) conn_table_expire(sock, to, _conn_expired_inb);
return rv;
}
@@ -664,7 +731,7 @@ static int conn_dhkey_new(ECPConnection *conn, unsigned char idx, ECPDHKey *key)
if (idx >= ECP_MAX_CONN_KEY) return ECP_ERR_ECDH_IDX;
#ifdef ECP_WITH_HTABLE
- if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn) && conn->key[idx].valid) {
+ if (ecp_conn_is_outb(conn) && _ecp_conn_is_reg(conn) && conn->key[idx].valid) {
ecp_ht_remove(sock->conn_table.keys, &conn->key[idx].public);
}
#endif
@@ -672,7 +739,7 @@ static int conn_dhkey_new(ECPConnection *conn, unsigned char idx, ECPDHKey *key)
conn->key[idx] = *key;
#ifdef ECP_WITH_HTABLE
- if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn)) {
+ if (ecp_conn_is_outb(conn) && _ecp_conn_is_reg(conn)) {
int rv;
rv = ecp_ht_insert(sock->conn_table.keys, &conn->key[idx].public, conn);
@@ -689,7 +756,7 @@ static void conn_dhkey_del(ECPConnection *conn, unsigned char idx) {
if (idx >= ECP_MAX_CONN_KEY) return;
#ifdef ECP_WITH_HTABLE
- if (ecp_conn_is_outb(conn) && ecp_conn_is_reg(conn) && conn->key[idx].valid) {
+ if (ecp_conn_is_outb(conn) && _ecp_conn_is_reg(conn) && conn->key[idx].valid) {
ecp_ht_remove(sock->conn_table.keys, &conn->key[idx].public);
}
#endif
@@ -723,7 +790,7 @@ static ECPDHPub *conn_dhkey_get_remote(ECPConnection *conn, unsigned char idx) {
}
/* node will send public key */
-static void conn_dhkey_get_pub(ECPConnection *conn, unsigned char idx) {
+static void conn_dhkey_send_pub(ECPConnection *conn, unsigned char idx) {
unsigned char _idx;
int i;
@@ -754,10 +821,10 @@ static int conn_dhkey_set_pub(ECPConnection *conn, unsigned char idx, ecp_ecdh_p
_idx = idx % ECP_MAX_NODE_KEY;
key = &conn->rkey[_idx];
- if (key->valid && (memcmp(public, &key->public, sizeof(key->public)) == 0)) return ECP_ERR_ECDH_KEY_DUP;
+ if (key->valid && (memcmp(public, &key->public, sizeof(key->public)) == 0)) return ECP_ERR_DUP;
#ifdef ECP_WITH_HTABLE
- if (ecp_conn_is_inb(conn) && ecp_conn_is_reg(conn) && (key->valid)) {
+ if (ecp_conn_is_inb(conn) && _ecp_conn_is_reg(conn) && (key->valid)) {
ecp_ht_remove(sock->conn_table.keys, &key->public);
}
#endif
@@ -766,7 +833,7 @@ static int conn_dhkey_set_pub(ECPConnection *conn, unsigned char idx, ecp_ecdh_p
key->valid = 1;
#ifdef ECP_WITH_HTABLE
- if (ecp_conn_is_inb(conn) && ecp_conn_is_reg(conn)) {
+ if (ecp_conn_is_inb(conn) && _ecp_conn_is_reg(conn)) {
int rv;
rv = ecp_ht_insert(sock->conn_table.keys, &key->public, conn);
@@ -847,24 +914,11 @@ static int conn_shkey_set(ECPConnection *conn, unsigned char s_idx, unsigned cha
return ECP_OK;
}
-int ecp_conn_alloc(ECPSocket *sock, unsigned char ctype, ECPConnection **_conn) {
+ECPConnection *ecp_conn_new_inb(ECPSocket *sock, unsigned char ctype) {
ECPContext *ctx = sock->ctx;
- ECPConnection *conn;
- int rv;
- if (ctx->conn_alloc == NULL) return ECP_ERR_ALLOC;
-
- conn = ctx->conn_alloc(sock, ctype);
- if (conn == NULL) return ECP_ERR_ALLOC;
-
- *_conn = conn;
- return ECP_OK;
-}
-
-void ecp_conn_free(ECPConnection *conn) {
- ECPContext *ctx = conn->sock->ctx;
-
- if (ctx->conn_free) ctx->conn_free(conn);
+ if (ctx->conn_new) return ctx->conn_new(sock, ctype);
+ return NULL;
}
void ecp_conn_init(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
@@ -878,138 +932,146 @@ void ecp_conn_init(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
conn->key_next = ECP_ECDH_IDX_INV;
conn->rkey_curr = ECP_ECDH_IDX_INV;
arc4random_buf(&conn->nonce_out, sizeof(conn->nonce_out));
+ conn->access_ts = ecp_tm_get_s();
}
-void ecp_conn_reinit(ECPConnection *conn) {
- conn->flags = 0;
+int ecp_conn_reset(ECPConnection *conn) {
+ if (conn->flags) return ECP_ERR;
+
+ conn->key_curr = ECP_ECDH_IDX_INV;
conn->key_next = ECP_ECDH_IDX_INV;
conn->rkey_curr = ECP_ECDH_IDX_INV;
memset(&conn->key, 0, sizeof(conn->key));
memset(&conn->rkey, 0, sizeof(conn->rkey));
memset(&conn->shkey, 0, sizeof(conn->shkey));
arc4random_buf(&conn->nonce_out, sizeof(conn->nonce_out));
+ conn->nonce_in = 0;
+ conn->nonce_map = 0;
+
+ return ECP_OK;
}
-int ecp_conn_create(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
+int ecp_conn_create(ECPConnection *conn, ECPConnection *parent) {
int rv;
+#ifdef ECP_WITH_VCONN
+ unsigned short pcount;
- ecp_conn_init(conn, sock, ctype);
+ pcount = parent ? parent->pcount + 1 : 0;
+ if (pcount > ECP_MAX_PARENT) return ECP_ERR_MAX_PARENT;
+#endif
#ifdef ECP_WITH_PTHREAD
rv = pthread_mutex_init(&conn->mutex, NULL);
if (rv) return ECP_ERR;
#endif
- return ECP_OK;
-}
-
-int ecp_conn_create_inb(ECPConnection *conn, ECPSocket *sock, unsigned char ctype) {
- int rv;
-
- rv = ecp_conn_create(conn, sock, ctype);
- if (rv) return rv;
-
- ecp_conn_set_inb(conn);
-
-#ifdef ECP_WITH_VCONN
- if (conn->parent) {
- ecp_conn_refcount_inc(conn->parent);
- }
+ rv = ecp_ext_conn_create(conn);
+ if (rv) {
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_destroy(&conn->mutex);
#endif
- return ECP_OK;
-}
-
-void ecp_conn_destroy(ECPConnection *conn) {
-#ifdef ECP_WITH_VCONN
- if (ecp_conn_is_inb(conn) && conn->parent) {
- ecp_conn_refcount_dec(conn->parent);
+ return ECP_ERR;
}
-#endif
- ecp_ext_conn_destroy(conn);
+#ifdef ECP_WITH_VCONN
+ if (parent) {
+ conn->parent = parent;
+ conn->pcount = pcount;
-#ifdef ECP_WITH_PTHREAD
- pthread_mutex_destroy(&conn->mutex);
+ ecp_conn_refcount_inc(parent);
+ }
#endif
-}
-
-void ecp_conn_set_flags(ECPConnection *conn, unsigned char flags) {
- flags &= flags & ECP_CONN_FLAG_MASK;
- conn->flags_im |= flags;
-}
-
-void ecp_conn_clr_flags(ECPConnection *conn, unsigned char flags) {
- flags &= flags & ECP_CONN_FLAG_MASK;
- conn->flags_im &= ~flags;
-}
-
-void ecp_conn_set_remote_key(ECPConnection *conn, ECPDHPub *key) {
- conn->remote.key_perma = *key;
-}
-void ecp_conn_set_remote_addr(ECPConnection *conn, ecp_tr_addr_t *addr) {
- conn->remote.addr = *addr;
+ return ECP_OK;
}
-int ecp_conn_init_inb(ECPConnection *conn, ECPConnection *parent, unsigned char s_idx, unsigned char c_idx, ecp_ecdh_public_t *public, ECPDHPub *remote_key, ecp_aead_key_t *shkey) {
+int ecp_conn_create_inb(ECPConnection *conn, ECPConnection *parent, unsigned char s_idx, unsigned char c_idx, ecp_ecdh_public_t *public, ECPDHPub *remote_key, ecp_aead_key_t *shkey) {
ECPSocket *sock = conn->sock;
- unsigned short pcount;
int rv;
-#ifdef ECP_WITH_VCONN
- pcount = (parent ? parent->pcount + 1 : 0);
- if (pcount > ECP_MAX_PARENT) return ECP_ERR_MAX_PARENT;
-#endif
-
if (ecp_conn_has_vbox(conn) && ((remote_key == NULL) || !remote_key->valid)) return ECP_ERR_VBOX;
+ ecp_conn_set_inb(conn);
+
rv = conn_dhkey_set_pub(conn, c_idx, public);
if (rv) return rv;
rv = conn_shkey_set(conn, s_idx, c_idx, shkey);
if (rv) return rv;
-#ifdef ECP_WITH_VCONN
- conn->parent = parent;
- conn->pcount = pcount;
-#endif
-
+ ecp_conn_set_flags(conn, ECP_CONN_FLAG_GC);
conn->refcount = 1;
conn->key_curr = s_idx;
conn->rkey_curr = c_idx;
- if (remote_key && remote_key->valid) conn->remote.key_perma = *remote_key;
+ if (remote_key && remote_key->valid) {
+ conn->remote.key_perma = *remote_key;
+ } else {
+ ECPDHPub *key_perma = &conn->remote.key_perma;
+ memcpy(&key_perma->public, public, sizeof(key_perma->public));
+ }
- return ECP_OK;
+ rv = ecp_conn_create(conn, parent);
+ return rv;
+}
+
+int ecp_conn_create_outb(ECPConnection *conn, ECPConnection *parent, ECPNode *node) {
+ int rv;
+
+ ecp_conn_set_outb(conn);
+
+ conn->refcount = 1;
+ if (node) conn->remote = *node;
+
+ rv = ecp_conn_reset_outb(conn);
+ if (rv) return rv;
+
+ rv = ecp_conn_create(conn, parent);
+ return rv;
}
-int ecp_conn_init_outb(ECPConnection *conn, ECPNode *node) {
+int ecp_conn_reset_outb(ECPConnection *conn) {
ECPDHKey key;
- unsigned char key_curr;
int rv;
- if (conn->key_curr == ECP_ECDH_IDX_INV) {
- key_curr = 0;
- } else {
- key_curr = (conn->key_curr + 1) % ECP_MAX_CONN_KEY;
- }
+ conn->key_curr = 0;
+
rv = ecp_dhkey_gen(&key);
if (rv) return rv;
- rv = conn_dhkey_new(conn, key_curr, &key);
+ rv = conn_dhkey_new(conn, conn->key_curr, &key);
if (rv) return rv;
- if (node) conn->remote = *node;
- conn->key_curr = key_curr;
-
return ECP_OK;
}
+void ecp_conn_destroy(ECPConnection *conn) {
+#ifdef ECP_WITH_VCONN
+ if (conn->parent) {
+ ecp_conn_refcount_dec(conn->parent);
+ }
+#endif
+
+ ecp_ext_conn_destroy(conn);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_destroy(&conn->mutex);
+#endif
+
+ ecp_conn_free(conn);
+}
+
+void ecp_conn_free(ECPConnection *conn) {
+ ECPContext *ctx = conn->sock->ctx;
+
+ if (ctx->conn_free) ctx->conn_free(conn);
+}
+
int ecp_conn_insert(ECPConnection *conn) {
ECPSocket *sock = conn->sock;
int rv;
- ecp_conn_set_reg(conn);
+ _ecp_conn_set_reg(conn);
#ifdef ECP_WITH_PTHREAD
pthread_mutex_lock(&sock->conn_table.mutex);
@@ -1021,25 +1083,23 @@ int ecp_conn_insert(ECPConnection *conn) {
pthread_mutex_unlock(&sock->conn_table.mutex);
#endif
- if (rv) ecp_conn_clr_reg(conn);
+ if (rv) _ecp_conn_clr_reg(conn);
return rv;
}
-int ecp_conn_insert_inb(ECPConnection *conn) {
+int ecp_conn_insert_gc(ECPConnection *conn) {
ECPSocket *sock = conn->sock;
int rv;
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_lock(&sock->conn_table.mutex_inb);
- pthread_mutex_lock(&conn->mutex);
+ pthread_mutex_lock(&sock->conn_table.mutex_gc);
#endif
- rv = conn_table_insert_inb(conn);
+ rv = conn_table_insert_gc(conn);
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_unlock(&conn->mutex);
- pthread_mutex_unlock(&sock->conn_table.mutex_inb);
+ pthread_mutex_unlock(&sock->conn_table.mutex_gc);
#endif
return rv;
@@ -1053,9 +1113,9 @@ void ecp_conn_remove(ECPConnection *conn, unsigned short *refcount) {
pthread_mutex_lock(&conn->mutex);
#endif
- if (ecp_conn_is_reg(conn)) {
+ if (_ecp_conn_is_reg(conn)) {
conn_table_remove(conn);
- ecp_conn_clr_reg(conn);
+ _ecp_conn_clr_reg(conn);
}
if (refcount) *refcount = conn->refcount;
@@ -1082,57 +1142,64 @@ void ecp_conn_remove_addr(ECPConnection *conn) {
}
-int ecp_conn_open(ECPConnection *conn, ECPNode *node) {
+int _ecp_conn_open(ECPConnection *conn, ECPConnection *parent, ECPNode *node, int retry) {
int rv;
ssize_t _rv;
- rv = ecp_conn_init_outb(conn, node);
+ rv = ecp_conn_create_outb(conn, parent, node);
if (rv) return rv;
rv = ecp_conn_insert(conn);
- if (rv) return rv;
+ if (rv) {
+ ecp_conn_destroy(conn);
+ return rv;
+ }
- _rv = ecp_send_init_req(conn);
+ if (ecp_conn_is_gc(conn)) {
+ rv = ecp_conn_insert_gc(conn);
+ if (rv) {
+ ecp_conn_refcount_dec(conn);
+ _ecp_conn_close(conn);
+ return rv;
+ }
+ }
+
+ _rv = ecp_send_init_req(conn, retry);
if (_rv < 0) {
- ecp_timer_remove(conn);
- ecp_conn_remove(conn, NULL);
+ ecp_conn_refcount_dec(conn);
+ ecp_conn_close(conn);
return _rv;
}
+ ecp_conn_refcount_dec(conn);
+
return ECP_OK;
}
-int ecp_conn_reset(ECPConnection *conn) {
- unsigned short refcount = 0;
- int i;
+int ecp_conn_open(ECPConnection *conn, ECPNode *node) {
int rv;
- /* timer holds one reference to this connection */
- ecp_conn_remove(conn, &refcount);
- if (refcount > 1) return ECP_ERR_BUSY;
-
- ecp_conn_reinit(conn);
- if (rv) return rv;
-
- rv = ecp_conn_init_outb(conn, NULL);
- if (rv) return rv;
+ rv = _ecp_conn_open(conn, NULL, node, 1);
+ return rv;
+}
- rv = ecp_conn_insert(conn);
- if (rv) return rv;
+int ecp_conn_try_open(ECPConnection *conn, ECPNode *node) {
+ int rv;
- return ECP_OK;
+ rv = _ecp_conn_open(conn, NULL, node, 0);
+ return rv;
}
static void conn_close(ECPConnection *conn) {
- if (ecp_conn_is_open(conn)) {
+ if (_ecp_conn_is_open(conn)) {
ecp_close_handler_t handler;
- ecp_conn_clr_open(conn);
+ _ecp_conn_clr_open(conn);
handler = ecp_get_close_handler(conn);
if (handler) handler(conn);
+ ecp_ext_conn_close(conn);
}
ecp_conn_destroy(conn);
- if (ecp_conn_is_inb(conn)) ecp_conn_free(conn);
}
int _ecp_conn_close(ECPConnection *conn) {
@@ -1147,8 +1214,49 @@ int _ecp_conn_close(ECPConnection *conn) {
}
int ecp_conn_close(ECPConnection *conn) {
- if (ecp_conn_is_inb(conn)) return ECP_ERR;
- return _ecp_conn_close(conn);
+ int rv;
+
+ if (ecp_conn_is_gc(conn)) {
+ ecp_conn_mark_closed(conn);
+ rv = ECP_OK;
+ } else {
+ rv = _ecp_conn_close(conn);
+ }
+
+ return rv;
+}
+
+void ecp_conn_mark_closed(ECPConnection *conn) {
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_lock(&conn->mutex);
+#endif
+
+ _ecp_conn_set_closed(conn);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_unlock(&conn->mutex);
+#endif
+}
+
+int _ecp_conn_expired(ECPConnection *conn, ecp_sts_t now, ecp_sts_t to) {
+ if (_ecp_conn_is_closed(conn) || (ECP_STS_LT(conn->access_ts, now) && (now - conn->access_ts > to))) return 1;
+ return 0;
+}
+
+int ecp_conn_is_zombie(ECPConnection *conn, ecp_sts_t now, ecp_sts_t to) {
+ int z = 0;
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_lock(&conn->mutex);
+#endif
+
+ z = _ecp_conn_expired(conn, now, to);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_unlock(&conn->mutex);
+#endif
+
+ return z;
}
void ecp_conn_refcount_inc(ECPConnection *conn) {
@@ -1173,7 +1281,7 @@ void ecp_conn_refcount_dec(ECPConnection *conn) {
conn->refcount--;
refcount = conn->refcount;
- is_reg = ecp_conn_is_reg(conn);
+ is_reg = _ecp_conn_is_reg(conn);
#ifdef ECP_WITH_PTHREAD
pthread_mutex_unlock(&conn->mutex);
@@ -1182,6 +1290,24 @@ void ecp_conn_refcount_dec(ECPConnection *conn) {
if (!is_reg && (refcount == 0)) conn_close(conn);
}
+void ecp_conn_set_flags(ECPConnection *conn, unsigned char flags) {
+ flags &= ECP_CONN_FLAG_MASK;
+ conn->flags_im |= flags;
+}
+
+void ecp_conn_clr_flags(ECPConnection *conn, unsigned char flags) {
+ flags &= ECP_CONN_FLAG_MASK;
+ conn->flags_im &= ~flags;
+}
+
+void ecp_conn_set_remote_key(ECPConnection *conn, ECPDHPub *key) {
+ conn->remote.key_perma = *key;
+}
+
+void ecp_conn_set_remote_addr(ECPConnection *conn, ecp_tr_addr_t *addr) {
+ conn->remote.addr = *addr;
+}
+
int ecp_conn_dhkey_new(ECPConnection *conn) {
ECPSocket *sock = conn->sock;
ECPDHKey new_key;
@@ -1208,13 +1334,9 @@ int ecp_conn_dhkey_new(ECPConnection *conn) {
pthread_mutex_unlock(&conn->mutex);
if (ecp_conn_is_outb(conn)) pthread_mutex_unlock(&sock->conn_table.mutex);
#endif
- if (idx == ECP_ECDH_IDX_INV) return ECP_ERR_ECDH_IDX;
- if (rv) return rv;
-
- _rv = ecp_send_keyx_req(conn);
- if (_rv < 0) return _rv;
- return ECP_OK;
+ if (idx == ECP_ECDH_IDX_INV) return ECP_ERR_ECDH_IDX;
+ return rv;
}
int ecp_conn_dhkey_get(ECPConnection *conn, unsigned char idx, ECPDHKey *key) {
@@ -1274,7 +1396,6 @@ int ecp_conn_dhkey_get_pub(ECPConnection *conn, unsigned char *idx, ecp_ecdh_pub
#ifdef ECP_WITH_PTHREAD
if (will_send) pthread_mutex_lock(&conn->mutex);
#endif
-
} else {
ECPDHKey *key;
@@ -1282,7 +1403,7 @@ int ecp_conn_dhkey_get_pub(ECPConnection *conn, unsigned char *idx, ecp_ecdh_pub
pthread_mutex_lock(&conn->mutex);
#endif
- if (will_send) {
+ if (will_send && (conn->key_next != ECP_ECDH_IDX_INV)) {
_idx = conn->key_next;
} else {
_idx = conn->key_curr;
@@ -1296,7 +1417,7 @@ int ecp_conn_dhkey_get_pub(ECPConnection *conn, unsigned char *idx, ecp_ecdh_pub
if (!rv) memcpy(public, &key->public, sizeof(key->public));
}
- if (!rv && will_send) conn_dhkey_get_pub(conn, _idx);
+ if (!rv && will_send) conn_dhkey_send_pub(conn, _idx);
#ifdef ECP_WITH_PTHREAD
if (will_send || ecp_conn_is_outb(conn)) pthread_mutex_unlock(&conn->mutex);
@@ -1324,7 +1445,7 @@ int ecp_conn_dhkey_set_pub(ECPConnection *conn, unsigned char idx, ecp_ecdh_publ
if (ecp_conn_is_inb(conn)) pthread_mutex_unlock(&sock->conn_table.mutex);
#endif
- if (rv == ECP_ERR_ECDH_KEY_DUP) rv = ECP_OK;
+ if (rv == ECP_ERR_DUP) rv = ECP_OK;
return rv;
}
@@ -1344,7 +1465,7 @@ void ecp_conn_dhkey_set_curr(ECPConnection *conn) {
#endif
}
-void ecp_conn_handler_init(ECPConnHandler *handler, ecp_msg_handler_t handle_msg, ecp_open_handler_t handle_open, ecp_close_handler_t handle_close, ecp_open_send_t send_open) {
+void ecp_conn_handler_init(ECPConnHandler *handler, ecp_msg_handler_t handle_msg, ecp_open_handler_t handle_open, ecp_close_handler_t handle_close, ecp_send_open_t send_open) {
memset(handler, 0, sizeof(ECPConnHandler));
handler->handle_msg = handle_msg;
handler->handle_open = handle_open;
@@ -1356,87 +1477,56 @@ ecp_msg_handler_t ecp_get_msg_handler(ECPConnection *conn) {
ECPContext *ctx = conn->sock->ctx;
unsigned char ctype;
- ctype = conn->type;
+ ctype = conn->type & ECP_CTYPE_MASK;
if (ecp_conn_is_sys(conn)) {
- switch (ctype) {
-#ifdef ECP_WITH_DIR
- case ECP_CTYPE_DIR:
- return ecp_dir_handle_msg;
-#endif
-
-#ifdef ECP_WITH_VCONN
- case ECP_CTYPE_VCONN:
- case ECP_CTYPE_VLINK:
- return ecp_vconn_handle_msg;
-#endif
-
- default:
- return NULL;
- }
+ if (ctype >= ECP_MAX_CTYPE_SYS) return NULL;
+ return ctx->handler_sys[ctype] ? ctx->handler_sys[ctype]->handle_msg : NULL;
+ } else {
+ if (ctype >= ECP_MAX_CTYPE) return NULL;
+ return ctx->handler[ctype] ? ctx->handler[ctype]->handle_msg : NULL;
}
-
- if (ctype >= ECP_MAX_CTYPE) return NULL;
- return ctx->handler[ctype] ? ctx->handler[ctype]->handle_msg : NULL;
}
ecp_open_handler_t ecp_get_open_handler(ECPConnection *conn) {
ECPContext *ctx = conn->sock->ctx;
unsigned char ctype;
- ctype = conn->type;
+ ctype = conn->type & ECP_CTYPE_MASK;
if (ecp_conn_is_sys(conn)) {
- switch (ctype) {
-#ifdef ECP_WITH_DIR
- case ECP_CTYPE_DIR:
- return ecp_dir_handle_open;
-#endif
-
-#ifdef ECP_WITH_VCONN
- case ECP_CTYPE_VCONN:
- case ECP_CTYPE_VLINK:
- return ecp_vconn_handle_open;
-#endif
-
- default:
- return NULL;
- }
+ if (ctype >= ECP_MAX_CTYPE_SYS) return NULL;
+ return ctx->handler_sys[ctype] ? ctx->handler_sys[ctype]->handle_open : NULL;
+ } else {
+ if (ctype >= ECP_MAX_CTYPE) return NULL;
+ return ctx->handler[ctype] ? ctx->handler[ctype]->handle_open : NULL;
}
-
- if (ctype >= ECP_MAX_CTYPE) return NULL;
- return ctx->handler[ctype] ? ctx->handler[ctype]->handle_open : NULL;
}
ecp_close_handler_t ecp_get_close_handler(ECPConnection *conn) {
ECPContext *ctx = conn->sock->ctx;
unsigned char ctype;
- ctype = conn->type;
+ ctype = conn->type & ECP_CTYPE_MASK;
if (ecp_conn_is_sys(conn)) {
- switch (ctype) {
-#ifdef ECP_WITH_DIR
- case ECP_CTYPE_DIR:
- return NULL;
-#endif
-
-#ifdef ECP_WITH_VCONN
- case ECP_CTYPE_VCONN:
- case ECP_CTYPE_VLINK:
- return ecp_vconn_handle_close;
-#endif
-
- default:
- return NULL;
- }
+ if (ctype >= ECP_MAX_CTYPE_SYS) return NULL;
+ return ctx->handler_sys[ctype] ? ctx->handler_sys[ctype]->handle_close : NULL;
+ } else {
+ if (ctype >= ECP_MAX_CTYPE) return NULL;
+ return ctx->handler[ctype] ? ctx->handler[ctype]->handle_close : NULL;
}
-
- if (ctype >= ECP_MAX_CTYPE) return NULL;
- return ctx->handler[ctype] ? ctx->handler[ctype]->handle_close : NULL;
}
-ecp_dir_handler_t ecp_get_dir_handler(ECPConnection *conn) {
+ecp_send_open_t ecp_get_send_open_f(ECPConnection *conn) {
ECPContext *ctx = conn->sock->ctx;
+ unsigned char ctype;
- return ctx->handle_dir;
+ ctype = conn->type & ECP_CTYPE_MASK;
+ if (ecp_conn_is_sys(conn)) {
+ if (ctype >= ECP_MAX_CTYPE_SYS) return NULL;
+ return ctx->handler_sys[ctype] ? ctx->handler_sys[ctype]->send_open : NULL;
+ } else {
+ if (ctype >= ECP_MAX_CTYPE) return NULL;
+ return ctx->handler[ctype] ? ctx->handler[ctype]->send_open : NULL;
+ }
}
void ecp_err_handle(ECPConnection *conn, unsigned char mtype, int err) {
@@ -1454,6 +1544,7 @@ static ssize_t _send_ireq(ECPConnection *conn, ECPTimerItem *ti) {
ECPBuffer payload;
unsigned char pkt_buf[ECP_SIZE_PKT_BUF(0, ECP_MTYPE_INIT_REQ, conn)];
unsigned char pld_buf[ECP_SIZE_PLD_BUF(0, ECP_MTYPE_INIT_REQ, conn)];
+ ssize_t rv;
packet.buffer = pkt_buf;
packet.size = sizeof(pkt_buf);
@@ -1462,29 +1553,50 @@ static ssize_t _send_ireq(ECPConnection *conn, ECPTimerItem *ti) {
ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_INIT_REQ);
- return _ecp_pld_send(conn, &packet, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, NULL, NULL, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_INIT_REQ), 0, ti);
+ rv = _ecp_pld_send(conn, &packet, ECP_ECDH_IDX_PERMA, ECP_ECDH_IDX_INV, NULL, NULL, &payload, ECP_SIZE_PLD(0, ECP_MTYPE_INIT_REQ), 0, ti);
+ return rv;
}
static ssize_t _retry_ireq(ECPConnection *conn, ECPTimerItem *ti) {
+ unsigned short refcount = 0;
int rv;
+ /* timer holds one reference to this connection */
+ ecp_conn_remove(conn, &refcount);
+ if (refcount > 1) return ECP_ERR_BUSY;
+
rv = ecp_conn_reset(conn);
if (rv) return rv;
+ rv = ecp_conn_reset_outb(conn);
+ if (rv) return rv;
+
+ rv = ecp_conn_insert(conn);
+ if (rv) return rv;
+
return _send_ireq(conn, ti);
}
-ssize_t ecp_send_init_req(ECPConnection *conn) {
- ECPTimerItem ti;
+ssize_t ecp_send_init_req(ECPConnection *conn, int retry) {
+ ssize_t rv;
+
+ if (retry) {
+ ECPTimerItem ti;
- ecp_timer_item_init(&ti, conn, ECP_MTYPE_OPEN_REP, _retry_ireq, ECP_SEND_TRIES-1, ECP_SEND_TIMEOUT);
+ ecp_timer_item_init(&ti, conn, ECP_MTYPE_OPEN_REP, _retry_ireq, ECP_SEND_TRIES-1, ECP_SEND_TIMEOUT);
+
+ rv = _send_ireq(conn, &ti);
+ } else {
+ rv = _send_ireq(conn, NULL);
+ }
- return _send_ireq(conn, &ti);
+ return rv;
}
-ssize_t ecp_handle_init_req(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr, unsigned char c_idx, unsigned char *public_buf, ecp_aead_key_t *shkey) {
+ssize_t ecp_handle_init_req(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr, unsigned char c_idx, unsigned char *public_buf, ecp_aead_key_t *shkey, ECP2Buffer *bufs) {
ssize_t rv;
+ ecp_tr_release(bufs->packet, 1);
rv = ecp_send_init_rep(sock, parent, addr, c_idx, public_buf, shkey);
if (rv < 0) return rv;
@@ -1531,9 +1643,8 @@ ssize_t ecp_send_init_rep(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t
return rv;
}
-ssize_t ecp_handle_init_rep(ECPConnection *conn, unsigned char *msg, size_t msg_size) {
- ecp_open_send_t send_open_f;
- unsigned char ctype;
+ssize_t ecp_handle_init_rep(ECPConnection *conn, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs) {
+ ecp_send_open_t send_open_f;
unsigned char *cookie;
ssize_t rv;
int _rv;
@@ -1543,29 +1654,11 @@ ssize_t ecp_handle_init_rep(ECPConnection *conn, unsigned char *msg, size_t msg_
_rv = ecp_conn_dhkey_set_pub(conn, msg[0], (ecp_ecdh_public_t *)(msg+1));
if (_rv) return _rv;
- ctype = conn->type;
- send_open_f = NULL;
cookie = msg+1+ECP_SIZE_ECDH_PUB;
- if (ecp_conn_is_sys(conn)) {
- switch (ctype) {
-#ifdef ECP_WITH_VCONN
- case ECP_CTYPE_VCONN:
- case ECP_CTYPE_VLINK:
- send_open_f = ecp_vconn_send_open_req;
- break;
-#endif
-
- default:
- break;
- }
- } else {
- ECPContext *ctx = conn->sock->ctx;
-
- if (ctype >= ECP_MAX_CTYPE) return ECP_ERR_CTYPE;
- send_open_f = ctx->handler[ctype] ? ctx->handler[ctype]->send_open : NULL;
- }
+ send_open_f = ecp_get_send_open_f(conn);
if (send_open_f == NULL) send_open_f = ecp_send_open_req;
+ ecp_tr_release(bufs->packet, 1);
rv = send_open_f(conn, cookie);
if (rv < 0) return rv;
@@ -1684,17 +1777,27 @@ ssize_t ecp_handle_open_req(ECPSocket *sock, ECPConnection *parent, unsigned cha
remote_key.valid = 1;
}
- _rv = ecp_conn_alloc(sock, ctype, &conn);
+ conn = ecp_conn_new_inb(sock, ctype);
+ if (conn == NULL) return ECP_ERR_ALLOC;
+
+ _rv = ecp_conn_create_inb(conn, parent, s_idx, c_idx, (ecp_ecdh_public_t *)public_buf, remote_key.valid ? &remote_key : NULL, shkey);
if (_rv) return _rv;
- _rv = ecp_conn_init_inb(conn, parent, s_idx, c_idx, (ecp_ecdh_public_t *)public_buf, remote_key.valid ? &remote_key : NULL, shkey);
- if (!_rv) _rv = ecp_conn_insert(conn);
+ _rv = ecp_conn_insert(conn);
if (_rv) {
ecp_conn_destroy(conn);
- ecp_conn_free(conn);
return _rv;
}
+ if (ecp_conn_is_gc(conn)) {
+ _rv = ecp_conn_insert_gc(conn);
+ if (_rv) {
+ ecp_conn_refcount_dec(conn);
+ _ecp_conn_close(conn);
+ return _rv;
+ }
+ }
+
*_conn = conn;
/* handle_open will be called later from msg handler */
@@ -1718,77 +1821,75 @@ ssize_t ecp_send_open_rep(ECPConnection *conn) {
return rv;
}
-ssize_t ecp_handle_open(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs) {
- size_t rsize;
- ecp_open_handler_t handler;
- int rv = ECP_OK;
+ssize_t ecp_check_open(ECPConnection *conn, unsigned char mtype, unsigned char *msg, size_t msg_size) {
+ int is_open;
+ ssize_t rv;
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_lock(&conn->mutex);
+#endif
+
+ is_open = _ecp_conn_is_open(conn);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_unlock(&conn->mutex);
+#endif
+
+ if (is_open) return ECP_ERR;
if (mtype == ECP_MTYPE_OPEN_REQ) {
if (ecp_conn_is_outb(conn)) return ECP_ERR;
- rsize = 2;
- if (msg_size < rsize) return ECP_ERR_SIZE;
+ rv = 2;
+ if (msg_size < rv) return ECP_ERR_SIZE;
- if (msg[1]) rsize += ECP_SIZE_VBOX;
- if (msg_size < rsize) return ECP_ERR_SIZE;
+ if (msg[1]) rv += ECP_SIZE_VBOX;
+ if (msg_size < rv) return ECP_ERR_SIZE;
} else {
if (ecp_conn_is_inb(conn)) return ECP_ERR;
- rsize = 0;
+ rv = 0;
}
-#ifdef ECP_WITH_PTHREAD
- pthread_mutex_lock(&conn->mutex);
-#endif
-
- if (ecp_conn_is_open(conn)) rv = ECP_ERR;
- if (!rv) rv = ecp_ext_conn_open(conn);
- if (!rv) ecp_conn_set_open(conn);
+ return rv;
+}
-#ifdef ECP_WITH_PTHREAD
- pthread_mutex_unlock(&conn->mutex);
-#endif
+int ecp_handle_open(ECPConnection *conn, ECP2Buffer *bufs) {
+ ecp_open_handler_t handler;
+ int rv = ECP_OK;
+ rv = ecp_ext_conn_open(conn);
if (rv) return rv;
handler = ecp_get_open_handler(conn);
- if (handler) rv = handler(conn, bufs);
- if (rv) {
+ if (handler) {
+ rv = handler(conn, bufs);
+ if (rv) {
+ ecp_ext_conn_close(conn);
+ return rv;
+ }
+ }
+
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_lock(&conn->mutex);
+ pthread_mutex_lock(&conn->mutex);
#endif
- ecp_conn_clr_open(conn);
+ _ecp_conn_set_open(conn);
#ifdef ECP_WITH_PTHREAD
- pthread_mutex_unlock(&conn->mutex);
+ pthread_mutex_unlock(&conn->mutex);
#endif
- if (ecp_conn_is_inb(conn)) _ecp_conn_close(conn);
- return rv;
- }
-
if (ecp_conn_is_inb(conn)) {
- ssize_t _rv;
-
ecp_tr_release(bufs->packet, 1);
-
- _rv = ecp_send_open_rep(conn);
- if (_rv < 0) {
- _ecp_conn_close(conn);
- return _rv;
- }
- rv = ecp_conn_insert_inb(conn);
- if (rv) {
- _ecp_conn_close(conn);
- return rv;
- }
+ ecp_send_open_rep(conn);
} else if (ecp_conn_is_root(conn)) {
ecp_conn_remove_addr(conn);
}
- return rsize;
+
+ return ECP_OK;
}
-static ssize_t _send_keyx_req(ECPConnection *conn, ECPTimerItem *ti) {
+static ssize_t _send_kxreq(ECPConnection *conn, ECPTimerItem *ti) {
ECPBuffer packet;
ECPBuffer payload;
unsigned char pkt_buf[ECP_SIZE_PKT_BUF(1+ECP_SIZE_ECDH_PUB, ECP_MTYPE_KEYX_REQ, conn)];
@@ -1812,8 +1913,16 @@ static ssize_t _send_keyx_req(ECPConnection *conn, ECPTimerItem *ti) {
return rv;
}
-ssize_t ecp_send_keyx_req(ECPConnection *conn) {
- return ecp_timer_send(conn, _send_keyx_req, ECP_MTYPE_KEYX_REP, ECP_SEND_TRIES, ECP_SEND_TIMEOUT);
+ssize_t ecp_send_keyx_req(ECPConnection *conn, int retry) {
+ ssize_t rv;
+
+ if (retry) {
+ rv = ecp_timer_send(conn, _send_kxreq, ECP_MTYPE_KEYX_REP, ECP_SEND_TRIES, ECP_SEND_TIMEOUT);
+ } else {
+ rv = _send_kxreq(conn, NULL);
+ }
+
+ return rv;
}
ssize_t ecp_send_keyx_rep(ECPConnection *conn) {
@@ -1857,7 +1966,6 @@ ssize_t ecp_handle_keyx(ECPConnection *conn, unsigned char mtype, unsigned char
if (ecp_conn_is_outb(conn)) return ECP_ERR;
ecp_tr_release(bufs->packet, 1);
-
rv = ecp_send_keyx_rep(conn);
if (rv < 0) return rv;
}
@@ -1870,7 +1978,7 @@ ssize_t ecp_msg_handle(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype,
switch (mtype) {
case ECP_MTYPE_OPEN_REQ:
case ECP_MTYPE_OPEN_REP:
- return ecp_handle_open(conn, mtype, msg, msg_size, bufs);
+ return ecp_check_open(conn, mtype, msg, msg_size);
case ECP_MTYPE_KEYX_REQ:
case ECP_MTYPE_KEYX_REP:
@@ -1901,17 +2009,20 @@ ssize_t ecp_pld_handle_one(ECPConnection *conn, ecp_seq_t seq, unsigned char *pa
_rv = ecp_pld_get_type(payload, pld_size, &mtype);
if (_rv) return _rv;
- ecp_timer_pop(conn, mtype);
-
msg = ecp_pld_get_msg(payload, pld_size);
if (msg == NULL) return ECP_ERR;
hdr_size = msg - payload;
msg_size = pld_size - hdr_size;
rv = ecp_msg_handle(conn, seq, mtype, msg, msg_size, bufs);
- if (rv < 0) return rv;
+ ecp_timer_pop(conn, mtype);
+ if (rv < 0) {
+ ecp_err_handle(conn, mtype, rv);
+ return rv;
+ }
rv += hdr_size;
+
if (rv > pld_size) return ECP_ERR_SIZE;
return rv;
}
@@ -1920,7 +2031,7 @@ ssize_t ecp_pld_handle(ECPConnection *conn, ecp_seq_t seq, unsigned char *payloa
size_t pld_size = _pld_size;
ssize_t rv;
- rv = ecp_ext_pld_handle(conn, seq, payload, pld_size, bufs);
+ rv = ecp_ext_pld_handle_one(conn, seq, payload, pld_size, bufs);
if (rv < 0) return rv;
payload += rv;
@@ -1938,7 +2049,7 @@ ssize_t ecp_pld_handle(ECPConnection *conn, ecp_seq_t seq, unsigned char *payloa
return _pld_size;
}
-ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr, ECP2Buffer *bufs, size_t _pkt_size, ECPConnection **_conn, unsigned char **_payload, ecp_seq_t *_seq) {
+ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr, ECP2Buffer *bufs, size_t _pkt_size, ECPConnection **_conn, unsigned char **_payload, ecp_seq_t *_seq, int *is_open_msg) {
ECPConnection *conn = NULL;
unsigned char idx;
unsigned char s_idx;
@@ -1962,6 +2073,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
*_conn = NULL;
*_payload = NULL;
*_seq = 0;
+ *is_open_msg = 0;
packet = bufs->packet->buffer;
idx = packet[ECP_SIZE_PROTO];
@@ -1984,7 +2096,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
if (conn) {
is_inb = ecp_conn_is_inb(conn);
- is_open = ecp_conn_is_open(conn);
+ is_open = _ecp_conn_is_open(conn);
if (!is_open && !is_inb && (idx == ECP_ECDH_IDX_INV)) {
nonce_buf = packet+ECP_SIZE_PROTO+1;
@@ -2083,6 +2195,44 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
payload = bufs->payload->buffer;
rv = ecp_aead_dec(payload, bufs->payload->size, packet, pkt_size, &shkey, &nonce_pkt, is_inb ? ECP_NTYPE_INB : ECP_NTYPE_OUTB);
+
+ /* init reply collision */
+ if ((rv == ECP_ERR_DECRYPT) && conn && !is_open && !is_inb && (idx == ECP_ECDH_IDX_INV)) {
+ ECPConnection *_conn = conn;
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_lock(&sock->conn_table.mutex);
+#endif
+
+ conn = conn_table_search_addr(sock, addr);
+
+ while (conn && (rv == ECP_ERR_DECRYPT)) {
+ if (conn != _conn) {
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_lock(&conn->mutex);
+#endif
+
+ _rv = conn_shkey_get(conn, s_idx, c_idx, &shkey);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_unlock(&conn->mutex);
+#endif
+
+ if (_rv) rv = _rv;
+ if (rv == ECP_ERR_DECRYPT) rv = ecp_aead_dec(payload, bufs->payload->size, packet, pkt_size, &shkey, &nonce_pkt, ECP_NTYPE_OUTB);
+ }
+ if (rv == ECP_ERR_DECRYPT) conn = conn_table_search_addr_next(sock, addr, conn);
+ }
+
+ if (rv < 0) conn = NULL;
+ if (conn) ecp_conn_refcount_inc(conn);
+
+#ifdef ECP_WITH_PTHREAD
+ pthread_mutex_unlock(&sock->conn_table.mutex);
+#endif
+
+ ecp_conn_refcount_dec(_conn);
+ }
if (rv < 0) goto unpack_err;
pld_size = rv;
@@ -2108,11 +2258,8 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
case ECP_MTYPE_INIT_REQ: {
unsigned char _public_buf[ECP_SIZE_ECDH_PUB];
- /* we should release incoming packet before sending reply packet */
memcpy(_public_buf, public_buf, sizeof(_public_buf));
- ecp_tr_release(bufs->packet, 1);
-
- rv = ecp_handle_init_req(sock, parent, addr, c_idx, _public_buf, &shkey);
+ rv = ecp_handle_init_req(sock, parent, addr, c_idx, _public_buf, &shkey, bufs);
if (rv < 0) return rv;
rv += hdr_size;
@@ -2126,7 +2273,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
/* pass to payload handler */
nonce_in = nonce_pkt;
nonce_map = ECP_ACK_FULL;
- is_open = 1;
+ *is_open_msg = 1;
rv = 0;
break;
}
@@ -2158,10 +2305,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
switch (mtype) {
case ECP_MTYPE_INIT_REP: {
- /* we should release incoming packet before sending reply packet */
- ecp_tr_release(bufs->packet, 1);
-
- rv = ecp_handle_init_rep(conn, msg, msg_size);
+ rv = ecp_handle_init_rep(conn, msg, msg_size, bufs);
if (rv < 0) goto unpack_err;
rv += hdr_size;
@@ -2172,7 +2316,7 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
/* pass to payload handler */
nonce_in = nonce_pkt;
nonce_map = ECP_ACK_FULL;
- is_open = 1;
+ *is_open_msg = 1;
rv = 0;
break;
}
@@ -2187,16 +2331,16 @@ ssize_t ecp_unpack(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr,
}
if (conn) {
- if (is_open) {
+ if (is_open || *is_open_msg) {
#ifdef ECP_WITH_PTHREAD
pthread_mutex_lock(&conn->mutex);
#endif
conn->nonce_in = nonce_in;
conn->nonce_map = nonce_map;
- if (is_inb) {
- conn->access_ts = ecp_tm_get_tick();
- if (addr) conn->remote.addr = *addr;
+ conn->access_ts = ecp_tm_get_s();
+ if (is_inb && addr) {
+ conn->remote.addr = *addr;
}
#ifdef ECP_WITH_PTHREAD
@@ -2219,13 +2363,14 @@ unpack_err:
}
ssize_t ecp_pkt_handle(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *addr, ECP2Buffer *bufs, size_t pkt_size) {
- ECPConnection *conn = NULL;
+ ECPConnection *conn;
unsigned char *payload;
+ int is_open_msg;
ecp_seq_t seq;
size_t pld_size;
ssize_t rv;
- rv = ecp_unpack(sock, parent, addr, bufs, pkt_size, &conn, &payload, &seq);
+ rv = ecp_unpack(sock, parent, addr, bufs, pkt_size, &conn, &payload, &seq, &is_open_msg);
if (rv < 0) return rv;
pld_size = pkt_size - rv;
@@ -2235,7 +2380,7 @@ ssize_t ecp_pkt_handle(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *ad
}
if (pld_size) {
- rv = ecp_ext_pld_store(conn, seq, payload, pld_size, bufs);
+ rv = ecp_ext_pld_handle(conn, seq, payload, pld_size, bufs);
if (rv < 0) goto pkt_handle_fin;
payload += rv;
@@ -2250,6 +2395,16 @@ ssize_t ecp_pkt_handle(ECPSocket *sock, ECPConnection *parent, ecp_tr_addr_t *ad
pld_size -= rv;
}
+ if (is_open_msg) {
+ int _rv;
+
+ _rv = ecp_handle_open(conn, bufs);
+ if (_rv) {
+ rv = _rv;
+ goto pkt_handle_fin;
+ }
+ }
+
rv = pkt_size - pld_size;
pkt_handle_fin:
@@ -2483,8 +2638,8 @@ int ecp_pld_get_frag(unsigned char *pld, size_t pld_size, unsigned char *frag_cn
*frag_cnt = pld[1];
*frag_tot = pld[2];
*frag_size = \
- (pld[3] << 8) | \
- (pld[4]);
+ ((uint16_t)pld[3] << 8) | \
+ ((uint16_t)pld[4]);
return ECP_OK;
}