diff options
Diffstat (limited to 'ecp/src/ecp/core.c')
-rw-r--r-- | ecp/src/ecp/core.c | 963 |
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; } |