aboutsummaryrefslogtreecommitdiffstats
path: root/hicn-light/src/hicn/core/connection_table.h
blob: d32a5fee86e548d5e4360791aaa192cb7110d9aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
 * Copyright (c) 2020 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.h
 * \brief hICN connection_table
 *
 * The connection table is composed of :
 *  - a pool of connections allowing access through their id in constant time;
 *  - a set of indices in the form of hash table for efficient index lookups:
 *     . by name
 *     . by address pair
 *
 * For efficient index retrieval, the header will be prepended and the
 * resulting pointer will directly point to the connection pool.
 */

#ifndef HICNLIGHT_CONNECTION_TABLE_H
#define HICNLIGHT_CONNECTION_TABLE_H

#include "address_pair.h"
#include "connection.h"
#include "../base/hash.h"
#include "../base/khash.h"
#include "../base/pool.h"

#define _ct_var(x) _ct_var_##x

/* Hash functions for indices. */
#define address_pair_hash(pair) (hash32(pair, sizeof(address_pair_t)))
#define address_pair_hash_eq(a, b) (address_pair_hash(b) - address_pair_hash(a))

/* Hash table types for indices. */
KHASH_INIT(ct_pair, const address_pair_t *, unsigned, 0, address_pair_hash, address_pair_hash_eq);
KHASH_INIT(ct_name, const char *, unsigned, 0, str_hash, str_hash_eq);

typedef struct {
    size_t max_size;

    kh_ct_pair_t * id_by_pair;
    kh_ct_name_t * id_by_name;

    connection_t * connections; // pool
} connection_table_t;

/**
 * @brief Allocate a connection from the connection table.
 *
 * @param[in] table The connection table from which to allocate a connection.
 * @param[out] connection The pointer that will hold the allocated connection.
 * @param[in] pair The address pair associated to the connection (to update index).
 * @param[in] name The name associated to the connection (to update index).
 *
 * NOTE:
 *  - This function updates all indices from the connection table if the
 *  allocation is successful.
 *  - You should always check that the returned connection is not NULL, which
 *  would signal that the pool is exhausted and could not be extended.
 */
#define connection_table_allocate(TABLE, CONN, PAIR, NAME)                      \
do {                                                                            \
    pool_get((TABLE)->connections, CONN);                                       \
    if (CONN) {                                                                 \
        off_t _ct_var(id) = (CONN) - (TABLE)->connections;                      \
        int _ct_var(res);                                                       \
        khiter_t _ct_var(k);                                                    \
        _ct_var(k) = kh_put_ct_pair((TABLE)->id_by_pair, PAIR, &_ct_var(res));  \
        kh_value((TABLE)->id_by_pair, _ct_var(k)) = _ct_var(id);                \
        if (NAME) {                                                             \
            _ct_var(k) = kh_put_ct_name((TABLE)->id_by_name, (NAME), &_ct_var(res));\
            kh_value((TABLE)->id_by_name, _ct_var(k)) = _ct_var(id);            \
        }                                                                       \
    }                                                                           \
} while(0)

/**
 * @brief Deallocate a connection and return it to the connection table pool.
 *
 * @param[in] table The connection table to which the connection is returned.
 * @param[in] conn The connection that is returned to the pool.
 *
 * NOTE:
 *  - Upon returning a connection to the pool, all indices pointing to that
 *  connection are also cleared.
 */
#define connection_table_deallocate(TABLE, CONN)                                \
do {                                                                            \
    const address_pair_t * _ct_var(pair) = connection_get_pair(CONN);           \
    khiter_t _ct_var(k);                                                        \
    _ct_var(k) = kh_get_ct_pair((TABLE)->id_by_pair, _ct_var(pair));            \
    if (_ct_var(k) != kh_end((TABLE)->id_by_pair))                              \
        kh_del_ct_pair((TABLE)->id_by_pair, _ct_var(k));                        \
                                                                                \
    const char * _ct_var(name) = connection_get_name(CONN);                     \
    if (_ct_var(name)) {                                                        \
        _ct_var(k) = kh_get_ct_name((TABLE)->id_by_name, _ct_var(name));        \
        if (_ct_var(k) != kh_end((TABLE)->id_by_name))                          \
            kh_del_ct_name((TABLE)->id_by_name, _ct_var(k));                    \
    }                                                                           \
                                                                                \
    pool_put((TABLE)->connections, CONN);                                       \
} while(0)                                                                      \

/**
 * @brief Returns the length of the connection table, the number of active
 * connections.
 *
 * @param[in] table The connection table for which we retrieve the length.
 *
 * @return size_t The length of the connection table.
 *
 * NOTE:
 *  - The length of the connection table, that is the number of currently active
 *  connections.
 */
#define connection_table_len(table) (pool_len(table->connections))

/**
 * @brief Validate an index in the connection table.
 *
 * @param[in] table The connection table in which to validate an index.
 * @param[in] id The index of the connection to validate.
 *
 * @return bool A flag indicating whether the connection index is valid or not.
 */
#define connection_table_validate_id(table, id) \
    pool_validate_id((table)->connections, (id))

/**
 * @brief Return the connection corresponding to the specified index in the
 * connection table.
 *
 * @param[in] table The connection table for which to retrieve the connection.
 * @param[in] id The index for which to retrieve the connection.
 *
 * @return connection_t * The connection correponding to the specified index in
 * the connection table.
 *
 * @see connection_table_get_by_id
 *
 * NOTE:
 *  - In this function, the index is not validated.
 */
#define connection_table_at(table, id) ((table)->connections + id)

/**
 * @brief Return the connection corresponding to the specified and validated
 * index in the connection table.
 *
 * @param[in] table The connection table for which to retrieve the connection.
 * @param[in] id The index for which to retrieve the connection.
 *
 * @return connection_t * The connection correponding to the specified index in
 * the connection table.
 *
 * @see connection_table_get_by_id
 *
 * NOTE:
 *  - In this function, the index is validated.
 */
#define connection_table_get_by_id(table, id)   \
    connection_table_validate_id(table, id)     \
        ? connection_table_at(table, id) : NULL

/**
 * @brief Returns the index of a given connection in the connection table.
 *
 * @param[in] table The connection table from which to retrieve the index.
 * @param[in] conn The connection for which to retrieve the index.
 *
 * @return off_t The index of the specified connection in the connection table.
 */
#define connection_table_get_connection_id(table, conn) \
    (conn - table->connections)

#define connection_table_foreach(table, conn, BODY) \
    pool_foreach(table->connections, (conn), BODY)

#define connection_table_enumerate(table, i, conn, BODY) \
    pool_enumerate(table->connections, (i), (conn), BODY)

/**
 * @brief Create a new connection table (extended parameters).
 *
 * @param[in] init_size Initially allocated size (hint, 0 = use default value).
 * @param[in] max_size Maximum size (0 = unlimited).
 *
 * @return connection_table_t* The newly created connection table.
 */
connection_table_t * _connection_table_create(size_t init_size, size_t max_size);

/**
 * @brief Create a new connection table (minimal parameters).
 *
 * @return connection_table_t* The newly created connection table.
 */
#define connection_table_create() _connection_table_create(0, 0)

/**
 * @brief Free a connection table
 *
 * @param[in] table Connection table to free
 */
void connection_table_free(connection_table_t * table);

/**
 * @brief Retrieve a connection from the connection table by address pair.
 *
 * @param[in] table The connection table in which to search.
 * @param[in] pair The address pair to search for.
 *
 * @return connection_t * The connection matching the specified address pair, or
 * NULL if not found.
 */
connection_t * connection_table_get_by_pair(const connection_table_t * table,
        const address_pair_t * pair);

/**
 * @brief Return a connection index from the connection table by name.
 *
 * @param[in] table The connection table in which to search.
 * @param[in] name The name to search for.
 *
 * @return off_t The index of the connection matching the name, or
 * CONNECTION_ID_UNDEFINED if not found.
 */
off_t connection_table_get_id_by_name(const connection_table_t * table,
        const char * name);

/**
 * @brief Return a connection from the connection table by name.
 *
 * @param[in] table The connection table in which to search.
 * @param[in] name The name to search for.
 *
 * @return connection_t * The connection matching the name, or NULL if not
 * found.
 */
connection_t * connection_table_get_by_name(const connection_table_t * table,
        const char * name);

/**
 * @brief Remove a connection from the connection table by its index.
 *
 * @param[in] table The connection table from which to delete the connection.
 * @param[in] id The index of the connection to remove.
 */
void connection_table_remove_by_id(connection_table_t * table, off_t id);

#endif /* HICNLIGHT_CONNECTION_TABLE_H */