aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/core/connection_table.c
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-light/src/hicn/core/connection_table.c')
-rw-r--r--hicn-light/src/hicn/core/connection_table.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/hicn-light/src/hicn/core/connection_table.c b/hicn-light/src/hicn/core/connection_table.c
new file mode 100644
index 000000000..a6b114c01
--- /dev/null
+++ b/hicn-light/src/hicn/core/connection_table.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2021-2022 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * \file connection_table.c
+ * \brief Implementation of hICN connection table
+ */
+
+#include <hicn/util/log.h>
+#include <hicn/util/sstrncpy.h>
+
+#include "connection.h"
+#include "connection_table.h"
+
+/* This is only used as a hint for first allocation, as the table is resizeable
+ */
+#define DEFAULT_CONNECTION_TABLE_SIZE 64
+
+typedef struct {
+ char name[SYMBOLIC_NAME_LEN];
+} name_key_t;
+
+connection_table_t *_connection_table_create(size_t init_size,
+ size_t max_size) {
+ if (init_size == 0) init_size = DEFAULT_CONNECTION_TABLE_SIZE;
+
+ connection_table_t *table = malloc(sizeof(connection_table_t));
+ if (!table) return NULL;
+
+ table->max_size = max_size;
+
+ /* Initialize indices */
+ table->id_by_pair = kh_init_ct_pair();
+ table->pair_keys = slab_create(address_pair_t, SLAB_INIT_SIZE);
+ table->id_by_name = kh_init_ct_name();
+ table->name_keys = slab_create(name_key_t, SLAB_INIT_SIZE);
+
+ /*
+ * We start by allocating a reasonably-sized pool, as this will eventually
+ * be resized if needed.
+ */
+ pool_init(table->connections, init_size, 0);
+
+ return table;
+}
+
+void connection_table_free(connection_table_t *table) {
+ unsigned conn_id;
+ kh_foreach_value(table->id_by_name, conn_id, {
+ connection_t *connection = connection_table_get_by_id(table, conn_id);
+ const char *name = connection_get_name(connection);
+
+ INFO("Removing connection %s [%d]", name, connection->fd);
+ connection_finalize(connection);
+ });
+
+ kh_destroy_ct_pair(table->id_by_pair);
+ slab_free(table->pair_keys);
+ kh_destroy_ct_name(table->id_by_name);
+ slab_free(table->name_keys);
+
+ pool_free(table->connections);
+ free(table);
+}
+
+connection_t *connection_table_allocate(const connection_table_t *table,
+ const address_pair_t *pair,
+ const char *name) {
+ connection_t *conn = NULL;
+ pool_get(table->connections, conn);
+ if (!conn) return NULL;
+
+#ifdef __APPLE__
+ // set __uint8_t sin_len to 0
+ uint8_t *ptr = (uint8_t *)address_pair_get_local(pair);
+ *ptr = 0x0;
+ ptr = (uint8_t *)address_pair_get_remote(pair);
+ *ptr = 0x0;
+#endif /* __APPLE__ */
+
+ off_t id = conn - table->connections;
+ int rc;
+
+ // Add in name hash table
+ name_key_t *name_copy = slab_get(name_key_t, table->name_keys);
+ strcpy_s(name_copy->name, sizeof(name_key_t), name);
+
+ khiter_t k = kh_put_ct_name(table->id_by_name, name_copy->name, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_name, k) = (unsigned int)id;
+
+ // Add in pair hash table
+ address_pair_t *pair_copy = slab_get(address_pair_t, table->pair_keys);
+ memcpy(pair_copy, pair, sizeof(address_pair_t));
+
+ k = kh_put_ct_pair(table->id_by_pair, pair_copy, &rc);
+ assert(rc == KH_ADDED || rc == KH_RESET);
+ kh_value(table->id_by_pair, k) = (unsigned int)id;
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair));
+ return conn;
+}
+
+void connection_table_deallocate(const connection_table_t *table,
+ const connection_t *conn) {
+ const char *name = connection_get_name(conn);
+ const address_pair_t *pair = connection_get_pair(conn);
+
+#ifdef __APPLE__
+ // set __uint8_t sin_len to 0
+ uint8_t *ptr = (uint8_t *)address_pair_get_local(pair);
+ *ptr = 0x0;
+ ptr = (uint8_t *)address_pair_get_remote(pair);
+ *ptr = 0x0;
+#endif /* __APPLE__ */
+
+ // Remove from name hash table
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
+ assert(k != kh_end(table->id_by_name));
+ kh_del_ct_name(table->id_by_name, k);
+ slab_put(table->name_keys, kh_key(table->id_by_name, k));
+
+ // Remove from pair hash table
+ k = kh_get_ct_pair(table->id_by_pair, pair);
+ assert(k != kh_end(table->id_by_pair));
+ kh_del_ct_pair(table->id_by_pair, k);
+ slab_put(table->pair_keys, kh_key(table->id_by_pair, k));
+
+ assert(kh_size(table->id_by_name) == kh_size(table->id_by_pair));
+ pool_put(table->connections, conn);
+}
+
+connection_t *connection_table_get_by_pair(const connection_table_t *table,
+ const address_pair_t *pair) {
+#ifdef __APPLE__
+ // set __uint8_t sin_len to 0
+ uint8_t *ptr = (uint8_t *)address_pair_get_local(pair);
+ *ptr = 0x0;
+ ptr = (uint8_t *)address_pair_get_remote(pair);
+ *ptr = 0x0;
+#endif /* __APPLE__ */
+
+ khiter_t k = kh_get_ct_pair(table->id_by_pair, pair);
+ if (k == kh_end(table->id_by_pair)) return NULL;
+ return table->connections + kh_val(table->id_by_pair, k);
+}
+
+off_t connection_table_get_id_by_name(const connection_table_t *table,
+ const char *name) {
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
+ if (k == kh_end(table->id_by_name)) return CONNECTION_ID_UNDEFINED;
+ return kh_val(table->id_by_name, k);
+}
+
+connection_t *connection_table_get_by_name(const connection_table_t *table,
+ const char *name) {
+ unsigned conn_id = (unsigned int)connection_table_get_id_by_name(table, name);
+ if (!connection_id_is_valid(conn_id)) return NULL;
+ return connection_table_at(table, conn_id);
+}
+
+void connection_table_remove_by_id(connection_table_t *table, off_t id) {
+ connection_t *connection = connection_table_at(table, id);
+ INFO("Removing connection %d (%s)", id, connection_get_name(connection));
+
+ connection_table_deallocate(table, connection);
+}
+
+void connection_table_print_by_pair(const connection_table_t *table) {
+ const address_pair_t *k;
+ unsigned v;
+
+ char local_addr_str[NI_MAXHOST], remote_addr_str[NI_MAXHOST];
+ int local_port, remote_port;
+ connection_t *connection;
+ const char *name;
+
+ INFO("*** Connection table ***");
+ kh_foreach(table->id_by_pair, k, v, {
+ address_to_string(&(k->local), local_addr_str, &local_port);
+ address_to_string(&(k->remote), remote_addr_str, &remote_port);
+ connection = connection_table_get_by_id(table, v);
+ name = connection_get_name(connection);
+ INFO("(%s:%d - %s:%d)\t\t\t(%u, %s)", local_addr_str, local_port,
+ remote_addr_str, remote_port, v, name);
+ })
+}
+
+void connection_table_print_by_name(const connection_table_t *table) {
+ const char *k;
+ unsigned v;
+
+ connection_t *connection;
+ const char *name;
+
+ INFO("*** Connection table ***");
+ kh_foreach(table->id_by_name, k, v, {
+ connection = connection_table_get_by_id(table, v);
+ name = connection_get_name(connection);
+ INFO("(%s)\t\t\t(%u, %s)", k, v, name);
+ })
+}
+
+connection_t *_connection_table_get_by_id(connection_table_t *table, off_t id) {
+ return connection_table_get_by_id(table, id);
+}
+
+static inline u16 RAND16() { return rand() & 0xFFFF; }
+
+int connection_table_get_random_name(const connection_table_t *table,
+ char *name) {
+ int i, n_attempts = 2 * USHRT_MAX;
+ for (i = 0; i < n_attempts; i++) {
+ int rc = snprintf(name, SYMBOLIC_NAME_LEN, "conn%u", RAND16());
+ if (rc < 0 || rc >= SYMBOLIC_NAME_LEN) continue;
+
+ // Check if generated connection name is a duplicate
+ khiter_t k = kh_get_ct_name(table->id_by_name, name);
+ if (k == kh_end(table->id_by_name)) break;
+ }
+
+ if (i == n_attempts) {
+ ERROR("Unable to generate new unique connection name");
+ return -1;
+ }
+
+ return 0;
+}