Project Alice
Loading...
Searching...
No Matches
pcp_client_db.c
Go to the documentation of this file.
1/*
2 Copyright (c) 2014 by Cisco Systems, Inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#else
29#include "default_config.h"
30#endif
31
32#include <assert.h>
33#include <stddef.h>
34#include <stdint.h>
35#include <stdlib.h>
36#include <string.h>
37#include <stdio.h>
38#include <errno.h>
39#include "pcp.h"
40#include "pcp_utils.h"
41#include "pcp_client_db.h"
42#include "pcp_logger.h"
43
44#define EMPTY 0xFFFFFFFF
45#define PCP_INIT_SERVER_COUNT 5
46
47static uint32_t compute_flow_key(struct flow_key_data *kd)
48{
49 uint32_t h=0;
50 uint8_t *k=(uint8_t*)(kd + 1);
51
52 while ((void*)(k--) != (void*)kd) {
53 uint32_t ho=h & 0xff000000;
54 h=h << 8;
55 h=h ^ (ho >> 24);
56 h=h ^ *k;
57 }
58
59 h=(h * 0x9E3779B9) >> (32 - FLOW_HASH_BITS);
60
61 return h;
62}
63
65{
66 pcp_flow_t *flow;
67
69
70 assert(fkd && s);
71
72 flow=(pcp_flow_t*)calloc(1, sizeof(struct pcp_flow_s));
73 if (flow == NULL) {
75 "Malloc can't allocate enough memory for the pcp_flow.");
76 PCP_LOG(PCP_LOGLVL_ERR, "%s", "Returning NULL.");
78 return NULL;
79 }
80
81 flow->pcp_msg_len=0;
82 flow->pcp_server_indx=(s ? s->index : PCP_INV_SERVER);
83 flow->kd=*fkd;
84 flow->key_bucket=EMPTY;
85 flow->ctx=s->ctx;
86
88 return flow;
89}
90
92{
93 if (f) {
94 if (f->pcp_msg_buffer) {
95 free(f->pcp_msg_buffer);
96 f->pcp_msg_buffer=NULL;
97 }
98 f->pcp_msg_len=0;
99 }
100}
101
103{
104 pcp_server_t *s;
105
106 assert(f);
107
109
110 if (f->pcp_msg_buffer) {
111 free(f->pcp_msg_buffer);
112 }
113
114#ifdef PCP_EXPERIMENTAL
115 if (f->md_vals) {
116 free(f->md_vals);
117 }
118#endif
119
120#ifdef PCP_SADSCP
121 if (f->sadscp_app_name) {
122 free(f->sadscp_app_name);
123 }
124#endif
125
127 && ((s=get_pcp_server(f->ctx, f->pcp_server_indx)) != NULL)
128 && (s->ping_flow_msg == f)) {
129 s->ping_flow_msg=NULL;
130 }
131
132 free(f);
133 return PCP_ERR_SUCCESS;
134}
135
137{
138 uint32_t indx;
139 pcp_flow_t **fdb;
140 pcp_ctx_t *ctx;
141
142 if (!f) {
143 return PCP_ERR_BAD_ARGS;
144 }
145
146 ctx=f->ctx;
147
148 f->key_bucket=indx=compute_flow_key(&f->kd);
149 PCP_LOG(PCP_LOGLVL_DEBUG, "Adding flow %p, key_bucket %d",
150 f, f->key_bucket);
151
152 for (fdb=ctx->pcp_db.flows + indx; (*fdb) != NULL; fdb=&(*fdb)->next);
153
154 *fdb=f;
155 f->next=NULL;
156 ctx->pcp_db.flow_cnt++;
157
158 PCP_LOG(PCP_LOGLVL_DEBUG, "total Number of flows added %zu",
159 ctx->pcp_db.flow_cnt);
160
161 return PCP_ERR_SUCCESS;
162}
163
165{
166 pcp_flow_t **fdb;
167 uint32_t bucket;
168 uint32_t pcp_server_index;
169
170 if ((!fkd) || (!s) || (!s->ctx)) {
171 return NULL;
172 }
173 pcp_server_index=s->index;
174
175 bucket=compute_flow_key(fkd);
176 PCP_LOG(PCP_LOGLVL_DEBUG, "Computed key_bucket %d", bucket);
177 for (fdb=&s->ctx->pcp_db.flows[bucket]; (*fdb) != NULL; fdb=&(*fdb)->next) {
178 if (((*fdb)->pcp_server_indx == pcp_server_index)
179 && (0 == memcmp(fkd, &(*fdb)->kd, sizeof(*fkd)))) {
180 return *fdb;
181 }
182 }
183
184 return NULL;
185}
186
188{
189 pcp_flow_t **fdb=NULL;
190 pcp_ctx_t *ctx;
191
192 assert(f && f->ctx);
193
194 if (f->key_bucket == EMPTY) {
195 return PCP_ERR_NOT_FOUND;
196 }
197
198 ctx=f->ctx;
199 PCP_LOG(PCP_LOGLVL_DEBUG, "Removing flow %p, key_bucket %d",
200 f, f->key_bucket);
201
202 for (fdb=ctx->pcp_db.flows + f->key_bucket; (*fdb) != NULL;
203 fdb=&((*fdb)->next)) {
204 if (*fdb == f) {
205 (*fdb)->key_bucket=EMPTY;
206 (*fdb)=(*fdb)->next;
207 ctx->pcp_db.flow_cnt--;
208 return PCP_ERR_SUCCESS;
209 }
210 }
211
212 return PCP_ERR_NOT_FOUND;
213}
214
216{
217 pcp_flow_t *fdb, *fdb_next=NULL;
218 uint32_t indx;
219
220 assert(f && ctx);
221
222 for (indx=0; indx < FLOW_HASH_SIZE; ++indx) {
223 fdb=ctx->pcp_db.flows[indx];
224 while (fdb != NULL) {
225 fdb_next=(fdb->next);
226 if ((*f)(fdb, data)) {
227 return PCP_ERR_SUCCESS;
228 }
229 fdb=fdb_next;
230 }
231
232 }
233
234 return PCP_ERR_NOT_FOUND;
235}
236
237#ifdef PCP_EXPERIMENTAL
238void pcp_db_add_md(pcp_flow_t *f, uint16_t md_id, void *val, size_t val_len)
239{
240 md_val_t *md;
241 uint32_t i;
242
243 assert(f);
244
245 for (i=f->md_val_count, md=f->md_vals; i>0 && md!=NULL; --i, ++md)
246 {
247 if (md->md_id == md_id) {
248 break;
249 }
250 }
251 if (i==0) {
252 md = NULL;
253 }
254
255 if (!md) {
256 md = (md_val_t*) realloc(f->md_vals,
257 sizeof(f->md_vals[0])*(f->md_val_count+1));
258 if (!md) { //LCOV_EXCL_START
259 return;
260 } //LCOV_EXCL_STOP
261 f->md_vals = md;
262 md = f->md_vals + f->md_val_count++;
263 }
264 md->md_id = md_id;
265 if ((val_len>0)&&(val!=NULL)) {
266 md->val_len = val_len > sizeof(md->val_buf) ?
267 sizeof(md->val_buf) : val_len;
268 memcpy(md->val_buf, val, md->val_len);
269 } else {
270 md->val_len=0;
271 }
272}
273#endif
274
275int pcp_new_server(pcp_ctx_t *ctx, struct in6_addr *ip, uint16_t port, uint32_t scope_id)
276{
277 uint32_t i;
278 pcp_server_t *ret=NULL;
279
281
282 assert(ctx && ip);
283
284 //initialize array of pcp servers, if not already initialized
285 if (!ctx->pcp_db.pcp_servers) {
287 sizeof(*ctx->pcp_db.pcp_servers));
288 if (!ctx->pcp_db.pcp_servers) {
289 char buff[ERR_BUF_LEN];
290 pcp_strerror(errno, buff, sizeof(buff));
291 PCP_LOG(PCP_LOGLVL_ERR, "Error (%s) occurred during realloc ",
292 buff);
294 return PCP_ERR_NO_MEM;
295 }
297 }
298
299 //find first unused record
300 for (i=0; i < ctx->pcp_db.pcp_servers_length; ++i) {
301 pcp_server_t *s=ctx->pcp_db.pcp_servers + i;
302 if (s->server_state == pss_unitialized) {
303 ret=s;
304 break;
305 }
306 }
307
308 // if nothing available double the size of array
309 if (ret == NULL) {
310 ret=(pcp_server_t *)realloc(ctx->pcp_db.pcp_servers,
311 sizeof(ctx->pcp_db.pcp_servers[0])
312 * (ctx->pcp_db.pcp_servers_length << 1));
313 if (!ret) {
314 char buff[ERR_BUF_LEN];
315
316 pcp_strerror(errno, buff, sizeof(buff));
317 PCP_LOG(PCP_LOGLVL_ERR, "Error (%s) occurred during realloc ",
318 buff);
320 return PCP_ERR_NO_MEM;
321 }
322 ctx->pcp_db.pcp_servers=ret;
324 memset(ret, 0, sizeof(*ret)*ctx->pcp_db.pcp_servers_length);
325 ctx->pcp_db.pcp_servers_length<<=1;
326 }
327
328 ret->epoch=~uint32_t(0);
329#ifdef PCP_USE_IPV6_SOCKET
330 ret->af = AF_INET6;
331#else
332 ret->af=IN6_IS_ADDR_V4MAPPED(ip) ? AF_INET : AF_INET6;
333#endif
334 IPV6_ADDR_COPY((struct in6_addr*)ret->pcp_ip, ip);
335 ret->pcp_port=port;
336 ret->pcp_scope_id=scope_id;
337 ret->ctx=ctx;
340 createNonce(&ret->nonce);
341 ret->index=(uint32_t)(ret - ctx->pcp_db.pcp_servers);
342
344 return ret->index;
345}
346
347pcp_server_t *get_pcp_server(pcp_ctx_t *ctx, int pcp_server_index)
348{
350
351 assert(ctx);
352
353 if ((pcp_server_index < 0)
354 || ((unsigned)pcp_server_index >= ctx->pcp_db.pcp_servers_length)) {
355
356 PCP_LOG(PCP_LOGLVL_WARN, "server index(%d) out of bounds(%zu)",
357 pcp_server_index, ctx->pcp_db.pcp_servers_length);
359 return NULL;
360 }
361
362 if (ctx->pcp_db.pcp_servers[pcp_server_index].server_state
363 == pss_unitialized) {
364
366 return NULL;
367 }
368
370 return ctx->pcp_db.pcp_servers + pcp_server_index;
371}
372
374 void *data)
375{
376 uint32_t indx;
377 int ret=PCP_ERR_MAX_SIZE;
378
380
381 assert(ctx && f);
382
383 for (indx=0; indx < ctx->pcp_db.pcp_servers_length; ++indx) {
385 continue;
386 }
387 if ((*f)(ctx->pcp_db.pcp_servers + indx, data)) {
388 ret=PCP_ERR_SUCCESS;
389 break;
390 }
392 return (pcp_errno)ret;
393}
394
395typedef struct find_data {
396 struct in6_addr *ip;
399
400static int find_ip(pcp_server_t *s, void *data)
401{
402 find_data_t *fd=(find_data_t *)data;
403
404 if (IN6_ARE_ADDR_EQUAL(fd->ip, (struct in6_addr *) s->pcp_ip)) {
405
406 fd->found_server=s;
407 return 1;
408 }
409 return 0;
410}
411
412pcp_server_t *get_pcp_server_by_ip(pcp_ctx_t *ctx, struct in6_addr *ip)
413{
414 find_data_t fdata;
415
417
418 assert(ctx && ip);
419
420 fdata.found_server=NULL;
421 fdata.ip=ip;
422 pcp_db_foreach_server(ctx, find_ip, &fdata);
423
425 return fdata.found_server;
426}
427
429{
430 uint32_t i;
431
432 assert(ctx);
433
434 for (i=0; i < ctx->pcp_db.pcp_servers_length; ++i) {
435 pcp_server_t *s=ctx->pcp_db.pcp_servers + i;
437 if ((state != pss_unitialized) && (state != pss_allocated)) {
439 }
440 }
441 free(ctx->pcp_db.pcp_servers);
442 ctx->pcp_db.pcp_servers=NULL;
444}
#define assert(condition)
Definition: debug.h:74
#define PCP_MAX_SUPPORTED_VERSION
uint uint32_t
uchar uint8_t
@ PCP_LOGLVL_ERR
Definition: pcp.h:86
@ PCP_LOGLVL_DEBUG
Definition: pcp.h:90
@ PCP_LOGLVL_WARN
Definition: pcp.h:87
pcp_errno
Definition: pcp.h:65
@ PCP_ERR_SUCCESS
Definition: pcp.h:66
@ PCP_ERR_NO_MEM
Definition: pcp.h:73
@ PCP_ERR_BAD_ARGS
Definition: pcp.h:74
@ PCP_ERR_NOT_FOUND
Definition: pcp.h:78
@ PCP_ERR_MAX_SIZE
Definition: pcp.h:67
pcp_errno pcp_db_foreach_flow(pcp_ctx_t *ctx, pcp_db_flow_iterate f, void *data)
pcp_server_t * get_pcp_server(pcp_ctx_t *ctx, int pcp_server_index)
#define EMPTY
Definition: pcp_client_db.c:44
void pcp_flow_clear_msg_buf(pcp_flow_t *f)
Definition: pcp_client_db.c:91
pcp_errno pcp_db_add_flow(pcp_flow_t *f)
pcp_errno pcp_db_foreach_server(pcp_ctx_t *ctx, pcp_db_server_iterate f, void *data)
pcp_errno pcp_db_rem_flow(pcp_flow_t *f)
pcp_flow_t * pcp_create_flow(pcp_server_t *s, struct flow_key_data *fkd)
Definition: pcp_client_db.c:64
#define PCP_INIT_SERVER_COUNT
Definition: pcp_client_db.c:45
void pcp_db_free_pcp_servers(pcp_ctx_t *ctx)
pcp_server_t * get_pcp_server_by_ip(pcp_ctx_t *ctx, struct in6_addr *ip)
pcp_flow_t * pcp_get_flow(struct flow_key_data *fkd, pcp_server_t *s)
int pcp_new_server(pcp_ctx_t *ctx, struct in6_addr *ip, uint16_t port, uint32_t scope_id)
struct find_data find_data_t
pcp_errno pcp_delete_flow_intern(pcp_flow_t *f)
#define FLOW_HASH_BITS
Definition: pcp_client_db.h:61
#define FLOW_HASH_SIZE
Definition: pcp_client_db.h:62
int(* pcp_db_flow_iterate)(pcp_flow_t *f, void *data)
int(* pcp_db_server_iterate)(pcp_server_t *f, void *data)
#define PCP_INV_SERVER
Definition: pcp_client_db.h:46
pcp_errno run_server_state_machine(pcp_server_t *s, pcp_event_e event)
pcp_server_state_e
@ pss_unitialized
@ pss_allocated
@ pcpe_terminate
void pcp_strerror(int errnum, char *buf, size_t buflen)
Definition: pcp_logger.c:165
#define PCP_LOG_END(level)
Definition: pcp_logger.h:73
#define PCP_LOG_BEGIN(level)
Definition: pcp_logger.h:75
#define ERR_BUF_LEN
Definition: pcp_logger.h:29
#define PCP_LOG(level, fmt,...)
Definition: pcp_logger.h:71
#define IPV6_ADDR_COPY(dest, src)
Definition: pcp_utils.h:117
struct in6_addr * ip
pcp_server_t * found_server
pcp_server_t * pcp_servers
pcp_flow_t * flows[FLOW_HASH_SIZE]
struct pcp_ctx_s::pcp_client_db pcp_db
uint32_t pcp_server_indx
uint32_t pcp_msg_len
struct pcp_ctx_s * ctx
struct flow_key_data kd
struct pcp_flow_s * next
uint32_t key_bucket
char * pcp_msg_buffer
uint32_t index
uint16_t pcp_port
uint32_t pcp_ip[4]
pcp_flow_t * ping_flow_msg
uint8_t pcp_version
pcp_server_state_e server_state
uint32_t af
uint32_t pcp_scope_id
uint32_t epoch
pcp_ctx_t * ctx
struct pcp_nonce nonce