From 085a8ed013a7390eb01450293ccf1f154fbfecd5 Mon Sep 17 00:00:00 2001
From: Uros Majstorovic <majstor@majstor.org>
Date: Tue, 23 Apr 2024 21:12:51 +0200
Subject: fixed vconn ref count and hashtables

---
 ecp/src/ecp/core.h        |  18 ++++
 ecp/src/ecp/vconn/vconn.c | 256 +++++++++++++++++++++++++++-------------------
 ecp/src/ecp/vconn/vconn.h |   8 +-
 3 files changed, 173 insertions(+), 109 deletions(-)

(limited to 'ecp/src')

diff --git a/ecp/src/ecp/core.h b/ecp/src/ecp/core.h
index 7ee7a9a..a4ae5c9 100644
--- a/ecp/src/ecp/core.h
+++ b/ecp/src/ecp/core.h
@@ -306,6 +306,19 @@ typedef struct ECPConnTable {
 #endif
 } ECPConnTable;
 
+#ifdef ECP_WITH_VCONN
+#ifdef ECP_WITH_HTABLE
+typedef struct ECPVConnTable {
+    ecp_ht_table_t *vconn_keys;
+    ecp_ht_table_t *vlink_keys;
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_t vconn_keys_mutex;
+    pthread_mutex_t vlink_keys_mutex;
+#endif
+} ECPVConnTable;
+#endif
+#endif
+
 typedef struct ECPSocket {
     ECPContext *ctx;
     unsigned char running;
@@ -321,6 +334,11 @@ typedef struct ECPSocket {
     pthread_t rcvr_thd;
     pthread_mutex_t mutex;
 #endif
+#ifdef ECP_WITH_VCONN
+#ifdef ECP_WITH_HTABLE
+    ECPVConnTable vconn_table;
+#endif
+#endif
 } ECPSocket;
 
 typedef struct ECPConnection {
diff --git a/ecp/src/ecp/vconn/vconn.c b/ecp/src/ecp/vconn/vconn.c
index 28620a6..39da365 100644
--- a/ecp/src/ecp/vconn/vconn.c
+++ b/ecp/src/ecp/vconn/vconn.c
@@ -13,55 +13,47 @@
 
 #ifdef ECP_WITH_HTABLE
 
-static int insert_key_next(ECPVConnInb *vconn, unsigned char c_idx, ecp_ecdh_public_t *public) {
+static int insert_vconn_next(ECPVConnInb *vconn, unsigned char c_idx, ecp_ecdh_public_t *public) {
     ECPConnection *conn = &vconn->b;
     ECPSocket *sock = conn->sock;
     ECPDHPub *key = NULL;
     int rv = ECP_OK;
 
-    if (c_idx & ~ECP_ECDH_IDX_MASK) return ECP_ERR_ECDH_IDX;
-
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_lock(&conn->mutex);
 #endif
 
-    if (c_idx != vconn->key_next_curr) {
-        unsigned char _c_idx;
-
-        _c_idx = c_idx % ECP_MAX_NODE_KEY;
-        key = &vconn->key_next[_c_idx];
-
-        if (key->valid && (memcmp(public, &key->public, sizeof(key->public)) == 0)) {
-            key = NULL;
-        }
+    key = &vconn->vconn_next[c_idx % ECP_MAX_NODE_KEY];
+    if (key->valid && (memcmp(public, &key->public, sizeof(key->public)) == 0)) {
+        key = NULL;
     }
 
 #ifdef ECP_WITH_PTHREAD
     pthread_mutex_unlock(&conn->mutex);
 #endif
 
-    if (key) {
+    if (key == NULL) return ECP_OK;
+
 #ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&sock->conn_table.mutex);
-        pthread_mutex_lock(&conn->mutex);
+    pthread_mutex_lock(&sock->vconn_table.vconn_keys_mutex);
+    pthread_mutex_lock(&conn->mutex);
 #endif
 
-        if (key->valid) {
-            ecp_ht_remove(sock->conn_table.keys, &key->public);
-            key->valid = 0;
-        }
-        memcpy(&key->public, public, sizeof(key->public));
-        rv = ecp_ht_insert(sock->conn_table.keys, &key->public, conn);
-        if (!rv) {
-            key->valid = 1;
-            vconn->key_next_curr = c_idx;
-        }
+    if (key->valid) {
+        ecp_ht_remove(sock->vconn_table.vconn_keys, &key->public);
+        key->valid = 0;
+    }
+    memcpy(&key->public, public, sizeof(key->public));
+    rv = ecp_ht_insert(sock->vconn_table.vconn_keys, &key->public, conn);
+    if (!rv) {
+        key->valid = 1;
+        vconn->vconn_next_curr = c_idx;
+    }
 
 #ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&conn->mutex);
-        pthread_mutex_unlock(&sock->conn_table.mutex);
+    pthread_mutex_unlock(&conn->mutex);
+    pthread_mutex_unlock(&sock->vconn_table.vconn_keys_mutex);
 #endif
-    }
 
     return rv;
 }
@@ -69,32 +61,21 @@ static int insert_key_next(ECPVConnInb *vconn, unsigned char c_idx, ecp_ecdh_pub
 static ssize_t handle_next(ECPConnection *conn, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs) {
     ECPVConnInb *vconn = (ECPVConnInb *)conn;
     ECPSocket *sock = conn->sock;
-    int rv = ECP_OK;
 
     if (msg_size < ECP_SIZE_ECDH_PUB) return ECP_ERR_SIZE;
     if (ecp_conn_is_outb(conn)) return ECP_ERR;
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&sock->conn_table.mutex);
+    pthread_mutex_lock(&conn->mutex);
 #endif
 
-    if (vconn->next == NULL) {
-        vconn->next = ecp_ht_search(sock->conn_table.keys, (ecp_ecdh_public_t *)msg);
-        if (vconn->next) {
-            ecp_conn_refcount_inc(vconn->next);
-        } else {
-            rv = ECP_ERR_NEXT;
-        }
-    } else {
-        rv = ECP_ERR_NEXT;
-    }
+    memcpy(&vconn->vlink_next.public, msg, sizeof(vconn->vlink_next.public));
+    vconn->vlink_next.valid = 1;
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&sock->conn_table.mutex);
+    pthread_mutex_unlock(&conn->mutex);
 #endif
 
-    if (rv) return rv;
-
     return ECP_SIZE_ECDH_PUB;
 }
 
@@ -116,14 +97,37 @@ static ssize_t handle_relay(ECPConnection *conn, unsigned char *msg, size_t msg_
         /* forward message */
         case ECP_CTYPE_VCONN: {
             ECPVConnInb *vconn = (ECPVConnInb *)conn;
+            int insert_next = 0;
 
             if (ecp_conn_is_outb(conn)) return ECP_ERR;
 
-            conn_next = vconn->next;
+            _idx = (idx & 0x0F);
+            conn_next = NULL;
+
+            if (_idx & ~ECP_ECDH_IDX_MASK) return ECP_ERR_ECDH_IDX;
+
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_lock(&sock->vconn_table.vlink_keys_mutex);
+            pthread_mutex_lock(&conn->mutex);
+#endif
+
+            if (_idx != vconn->vconn_next_curr) insert_next = 1;
+
+            if (vconn->vlink_next.valid) conn_next = ecp_ht_search(sock->vconn_table.vlink_keys, &vconn->vlink_next.public);
             if (conn_next) {
-                _idx = (idx & 0x0F);
+                _rv = ecp_conn_refcount_inc(conn_next);
+                if (_rv) conn_next = NULL;
+            }
+
+#ifdef ECP_WITH_PTHREAD
+            pthread_mutex_unlock(&conn->mutex);
+            pthread_mutex_unlock(&sock->vconn_table.vlink_keys_mutex);
+#endif
 
-                _rv = insert_key_next(vconn, _idx, (ecp_ecdh_public_t *)(msg+ECP_SIZE_PROTO+1));
+            if (conn_next == NULL) return ECP_ERR_NEXT;
+
+            if (insert_next) {
+                _rv = insert_vconn_next(vconn, _idx, (ecp_ecdh_public_t *)(msg+ECP_SIZE_PROTO+1));
                 if (_rv) return _rv;
             }
 
@@ -133,18 +137,23 @@ static ssize_t handle_relay(ECPConnection *conn, unsigned char *msg, size_t msg_
         /* back message */
         case ECP_CTYPE_VLINK: {
 #ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&sock->conn_table.mutex);
+            pthread_mutex_lock(&sock->vconn_table.vconn_keys_mutex);
 #endif
 
-            conn_next = ecp_ht_search(sock->conn_table.keys, (ecp_ecdh_public_t *)(msg+ECP_SIZE_PROTO+1));
-            if (conn_next) ecp_conn_refcount_inc(conn_next);
+            conn_next = ecp_ht_search(sock->vconn_table.vconn_keys, (ecp_ecdh_public_t *)(msg+ECP_SIZE_PROTO+1));
+            if (conn_next) {
+                _rv = ecp_conn_refcount_inc(conn_next);
+                if (_rv) conn_next = NULL;
+            }
 
 #ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&sock->conn_table.mutex);
+            pthread_mutex_unlock(&sock->vconn_table.vconn_keys_mutex);
 #endif
 
+            if (conn_next == NULL) return ECP_ERR_NEXT;
+
             _idx = (idx & 0xF0) >> 4;
-            if (conn_next && (_idx == ECP_ECDH_IDX_PERMA)) {
+            if (_idx == ECP_ECDH_IDX_PERMA) {
                 /* this is init reply */
                 msg[ECP_SIZE_PROTO] = (ECP_ECDH_IDX_PERMA << 4) | ECP_ECDH_IDX_NOKEY;
                 memmove(msg+ECP_SIZE_PROTO+1, msg+ECP_SIZE_PROTO+1+ECP_SIZE_ECDH_PUB, msg_size-(ECP_SIZE_PROTO+1+ECP_SIZE_ECDH_PUB));
@@ -158,17 +167,13 @@ static ssize_t handle_relay(ECPConnection *conn, unsigned char *msg, size_t msg_
             return ECP_ERR_CTYPE;
     }
 
-    if (conn_next == NULL) return ECP_ERR_NEXT;
-
     payload.buffer = msg - ECP_SIZE_MTYPE;
     payload.size = bufs->payload->size - (payload.buffer - bufs->payload->buffer);
 
     ecp_pld_set_type(payload.buffer, payload.size, ECP_MTYPE_EXEC);
     rv = ecp_pld_send(conn_next, bufs->packet, &payload, ECP_SIZE_MTYPE + _msg_size, ECP_SEND_FLAG_REPLY);
 
-    if (conn->type == ECP_CTYPE_VLINK) {
-        ecp_conn_refcount_dec(conn_next);
-    }
+    ecp_conn_refcount_dec(conn_next);
 
     if (rv < 0) return rv;
     return msg_size;
@@ -233,9 +238,9 @@ void ecp_vconn_init_inb(ECPVConnInb *vconn, ECPSocket *sock) {
     ECPConnection *conn = &vconn->b;
 
     ecp_conn_init(conn, sock, ECP_CTYPE_VCONN);
-    vconn->next = NULL;
-    memset(vconn->key_next, 0, sizeof(vconn->key_next));
-    vconn->key_next_curr = ECP_ECDH_IDX_INV;
+    memset(&vconn->vlink_next, 0, sizeof(vconn->vlink_next));
+    memset(&vconn->vconn_next, 0, sizeof(vconn->vconn_next));
+    vconn->vconn_next_curr = ECP_ECDH_IDX_INV;
 }
 
 #endif  /* ECP_WITH_HTABLE */
@@ -260,18 +265,16 @@ int ecp_vconn_open(ECPVConnOutb *vconn, ECPConnection *conn, ECPNode *node) {
 }
 
 int ecp_vconn_handle_open(ECPConnection *conn, ECP2Buffer *bufs) {
-    int rv = ECP_OK;
-
-    if (ecp_conn_is_outb(conn)) {
-        ECPVConnOutb *vconn = (ECPVConnOutb *)conn;
+    ECPVConnOutb *vconn = (ECPVConnOutb *)conn;
+    int rv;
 
-        if (vconn->next == NULL) return ECP_ERR;
+    if (ecp_conn_is_inb(conn)) return ECP_OK;
+    if (vconn->next == NULL) return ECP_ERR;
 
-        /* we should release incoming packet before sending next open packet */
-        ecp_tr_release(bufs->packet, 1);
-        rv = _ecp_conn_open(vconn->next, conn, NULL, 1);
-        if (rv) rv = ECP_ERR_NEXT;
-    }
+    /* we should release incoming packet before sending next open packet */
+    ecp_tr_release(bufs->packet, 1);
+    rv = _ecp_conn_open(vconn->next, conn, NULL, 1);
+    if (rv) rv = ECP_ERR_NEXT;
 
     return rv;
 }
@@ -286,23 +289,21 @@ void ecp_vconn_handle_close(ECPConnection *conn) {
     if (ecp_conn_is_outb(conn)) return;
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&sock->conn_table.mutex);
+    pthread_mutex_lock(&sock->vconn_table.vconn_keys_mutex);
 #endif
 
     for (i=0; i<ECP_MAX_NODE_KEY; i++) {
         ECPDHPub *key;
 
-        key = &vconn->key_next[i];
+        key = &vconn->vconn_next[i];
         if (key->valid) {
-            ecp_ht_remove(sock->conn_table.keys, &key->public);
+            ecp_ht_remove(sock->vconn_table.vconn_keys, &key->public);
         }
     }
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&sock->conn_table.mutex);
+    pthread_mutex_unlock(&sock->vconn_table.vconn_keys_mutex);
 #endif
-
-    if (vconn->next) ecp_conn_refcount_dec(vconn->next);
 }
 
 #endif  /* ECP_WITH_HTABLE */
@@ -380,39 +381,22 @@ void ecp_vlink_init(ECPConnection *conn, ECPSocket *sock) {
 int ecp_vlink_handle_open(ECPConnection *conn, ECP2Buffer *bufs) {
     ECPSocket *sock = conn->sock;
     ECPDHPub *key;
-    int rv = ECP_OK;
-
-    key = &conn->remote.key_perma;
-
-#ifdef ECP_WITH_PTHREAD
-    pthread_mutex_lock(&sock->conn_table.mutex);
-    pthread_mutex_lock(&conn->mutex);
-#endif
+    int rv;
 
-    if (key->valid) {
-        ECPConnection *_conn;
+    if ((conn->parent == NULL) && ecp_conn_is_inb(conn)) return ECP_OK;
 
-        /* check for duplicates */
-        _conn = ecp_ht_search(sock->conn_table.keys, &key->public);
-        if (_conn) {
-#ifdef ECP_WITH_PTHREAD
-            pthread_mutex_lock(&_conn->mutex);
-#endif
-
-            _conn->remote.key_perma.valid = 0;
+    key = &conn->remote.key_perma;
+    if (!key->valid) return ECP_OK;
 
 #ifdef ECP_WITH_PTHREAD
-            pthread_mutex_unlock(&_conn->mutex);
+    pthread_mutex_lock(&sock->vconn_table.vlink_keys_mutex);
 #endif
 
-            ecp_ht_remove(sock->conn_table.keys, &key->public);
-        }
-        rv = ecp_ht_insert(sock->conn_table.keys, &key->public, conn);
-    }
+    ecp_ht_remove(sock->vconn_table.vlink_keys, &key->public);
+    rv = ecp_ht_insert(sock->vconn_table.vlink_keys, &key->public, conn);
 
 #ifdef ECP_WITH_PTHREAD
-    pthread_mutex_unlock(&conn->mutex);
-    pthread_mutex_unlock(&sock->conn_table.mutex);
+    pthread_mutex_unlock(&sock->vconn_table.vlink_keys_mutex);
 #endif
 
     return rv;
@@ -420,19 +404,22 @@ int ecp_vlink_handle_open(ECPConnection *conn, ECP2Buffer *bufs) {
 
 void ecp_vlink_handle_close(ECPConnection *conn) {
     ECPSocket *sock = conn->sock;
-    ECPDHPub *key = &conn->remote.key_perma;
+    ECPDHPub *key;
+
+    if ((conn->parent == NULL) && ecp_conn_is_inb(conn)) return;
+
+    key = &conn->remote.key_perma;
+    if (!key->valid) return;
 
-    if (key->valid) {
 #ifdef ECP_WITH_PTHREAD
-        pthread_mutex_lock(&sock->conn_table.mutex);
+    pthread_mutex_lock(&sock->vconn_table.vlink_keys_mutex);
 #endif
 
-        ecp_ht_remove(sock->conn_table.keys, &key->public);
+    ecp_ht_remove_kv(sock->vconn_table.vlink_keys, &key->public, conn);
 
 #ifdef ECP_WITH_PTHREAD
-        pthread_mutex_unlock(&sock->conn_table.mutex);
+    pthread_mutex_unlock(&sock->vconn_table.vlink_keys_mutex);
 #endif
-    }
 }
 
 #endif  /* ECP_WITH_HTABLE */
@@ -459,6 +446,63 @@ ssize_t ecp_vlink_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char m
     return rv;
 }
 
+int ecp_vconn_sock_create(ECPSocket *sock) {
+    int rv = ECP_OK;
+
+#ifdef ECP_WITH_HTABLE
+
+    memset(&sock->vconn_table, 0, sizeof(sock->vconn_table));
+
+#ifdef ECP_WITH_PTHREAD
+    rv = pthread_mutex_init(&sock->vconn_table.vconn_keys_mutex, NULL);
+    if (rv) {
+        return ECP_ERR;
+    }
+
+    rv = pthread_mutex_init(&sock->vconn_table.vlink_keys_mutex, NULL);
+    if (rv) {
+        pthread_mutex_destroy(&sock->vconn_table.vconn_keys_mutex);
+        return ECP_ERR;
+    }
+#endif
+
+    sock->vconn_table.vconn_keys = ecp_ht_create_keys();
+    if (sock->vconn_table.vconn_keys == NULL) rv = ECP_ERR_ALLOC;
+
+    if (!rv) {
+        sock->vconn_table.vlink_keys = ecp_ht_create_keys();
+        if (sock->vconn_table.vlink_keys == NULL) rv = ECP_ERR_ALLOC;
+    }
+
+    if (rv) {
+#ifdef ECP_WITH_PTHREAD
+        pthread_mutex_destroy(&sock->vconn_table.vlink_keys_mutex);
+        pthread_mutex_destroy(&sock->vconn_table.vconn_keys_mutex);
+#endif
+
+        if (sock->vconn_table.vlink_keys) ecp_ht_destroy(sock->vconn_table.vlink_keys);
+        if (sock->vconn_table.vconn_keys) ecp_ht_destroy(sock->vconn_table.vconn_keys);
+    }
+
+#endif  /* ECP_WITH_HTABLE */
+
+    return rv;
+}
+
+void ecp_vconn_sock_destroy(ECPSocket *sock) {
+#ifdef ECP_WITH_HTABLE
+
+    ecp_ht_destroy(sock->vconn_table.vlink_keys);
+    ecp_ht_destroy(sock->vconn_table.vconn_keys);
+
+#ifdef ECP_WITH_PTHREAD
+    pthread_mutex_destroy(&sock->vconn_table.vlink_keys_mutex);
+    pthread_mutex_destroy(&sock->vconn_table.vconn_keys_mutex);
+#endif
+
+#endif  /* ECP_WITH_HTABLE */
+}
+
 int ecp_vconn_handler_init(ECPContext *ctx, ECPConnHandler *vconn_handler) {
     int rv;
 
diff --git a/ecp/src/ecp/vconn/vconn.h b/ecp/src/ecp/vconn/vconn.h
index 9bdb3d3..f343846 100644
--- a/ecp/src/ecp/vconn/vconn.h
+++ b/ecp/src/ecp/vconn/vconn.h
@@ -13,9 +13,9 @@
 
 typedef struct ECPVConnInb {
     ECPConnection b;
-    ECPConnection *next;
-    ECPDHPub key_next[ECP_MAX_NODE_KEY];
-    unsigned char key_next_curr;
+    ECPDHPub vlink_next;
+    ECPDHPub vconn_next[ECP_MAX_NODE_KEY];
+    unsigned char vconn_next_curr;
 } ECPVConnInb;
 
 typedef struct ECPVConnOutb {
@@ -45,5 +45,7 @@ void ecp_vlink_handle_close(ECPConnection *conn);
 #endif
 ssize_t ecp_vlink_handle_msg(ECPConnection *conn, ecp_seq_t seq, unsigned char mtype, unsigned char *msg, size_t msg_size, ECP2Buffer *bufs);
 
+int ecp_vconn_sock_create(ECPSocket *sock);
+void ecp_vconn_sock_destroy(ECPSocket *sock);
 int ecp_vconn_handler_init(ECPContext *ctx, ECPConnHandler *vconn_handler);
 int ecp_vlink_handler_init(ECPContext *ctx, ECPConnHandler *vlink_handler);
-- 
cgit v1.2.3