Coverage Report

Created: 2025-07-09 06:29

/src/opensips/usr_avp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 * History:
21
 * ---------
22
 *  2004-07-21  created (bogdan)
23
 *  2004-10-09  interface more flexible - more function available (bogdan)
24
 *  2004-11-07  AVP string values are kept 0 terminated (bogdan)
25
 *  2004-11-14  global aliases support added (bogdan)
26
 */
27
28
29
#include <assert.h>
30
#include <ctype.h>
31
#include <string.h>
32
#include <stdlib.h>
33
34
#include "sr_module.h"
35
#include "dprint.h"
36
#include "str.h"
37
#include "ut.h"
38
#include "mem/shm_mem.h"
39
#include "mem/mem.h"
40
#include "usr_avp.h"
41
#include "locking.h"
42
43
#include "map.h"
44
45
46
static gen_lock_t *extra_lock;
47
static struct usr_avp *global_avps = 0;
48
static struct usr_avp **crt_avps  = &global_avps;
49
static struct usr_avp **crt_bavps;
50
51
static map_t avp_map = 0;
52
static map_t avp_map_shm = 0;
53
static int last_avp_index = 0;
54
/* it is also used to indicate that the extra AVPs that are stored in the
55
 * shared memory have been initialized */
56
static int *last_avp_index_shm = 0;
57
58
0
#define p2int(_p) (int)(unsigned long)(_p)
59
0
#define int2p(_i) (void *)(unsigned long)(_i)
60
61
int init_global_avps(void)
62
0
{
63
  /* initialize map for static avps */
64
0
  avp_map = map_create(0);
65
0
  if (!avp_map) {
66
0
    LM_ERR("cannot create avp_map\n");
67
0
    return -1;
68
0
  }
69
0
  return 0;
70
0
}
71
72
73
int init_extra_avps(void)
74
0
{
75
0
  extra_lock = lock_alloc();
76
0
  if (!extra_lock) {
77
0
    LM_ERR("cannot allocate lock\n");
78
0
    return -1;
79
0
  }
80
0
  if (!lock_init(extra_lock)) {
81
0
    LM_ERR("cannot init lock\n");
82
0
    return -1;
83
0
  }
84
0
  last_avp_index_shm = shm_malloc(sizeof(int));
85
0
  if (!last_avp_index_shm) {
86
0
    LM_ERR("not enough shm mem\n");
87
0
    return -1;
88
0
  }
89
0
  *last_avp_index_shm = last_avp_index;
90
  /* initialize map for dynamic avps */
91
0
  avp_map_shm = map_create(AVLMAP_SHARED);
92
0
  if (!avp_map_shm) {
93
0
    LM_ERR("cannot create shared avp_map\n");
94
0
    return -1;
95
0
  }
96
0
  return 0;
97
0
}
98
99
100
struct usr_avp* new_avp(unsigned short flags, int id, int_str val)
101
0
{
102
0
  struct usr_avp *avp;
103
0
  str *s;
104
0
  int len;
105
106
0
  assert( crt_avps!=0 );
107
108
0
  if (id < 0) {
109
0
    LM_ERR("invalid AVP name!\n");
110
0
    goto error;
111
0
  }
112
113
  /* compute the required mem size */
114
0
  len = sizeof(struct usr_avp);
115
0
  if (flags & AVP_VAL_STR)
116
0
    len += sizeof(str)-sizeof(void*) + (val.s.len+1);
117
118
0
  avp = (struct usr_avp*)shm_malloc( len );
119
0
  if (avp==0) {
120
0
    LM_ERR("no more shm mem\n");
121
0
    goto error;
122
0
  }
123
124
0
  avp->flags = flags;
125
0
  avp->id = id ;
126
127
0
  if (flags & AVP_VAL_STR) {
128
    /* avp type ID, str value */
129
0
    s = (str *)&avp->data;
130
0
    s->len = val.s.len;
131
0
    s->s = (char*)s + sizeof(str);
132
0
    memcpy( s->s, val.s.s , s->len);
133
0
    s->s[s->len] = 0;
134
0
  } else if (flags & AVP_VAL_NULL) {
135
0
                avp->data = NULL;
136
0
  } else {
137
0
    avp->data = (void *)(long)val.n;
138
0
  }
139
140
0
  return avp;
141
0
error:
142
0
  return NULL;
143
0
}
144
145
int add_avp(unsigned short flags, int name, int_str val)
146
0
{
147
0
  struct usr_avp* avp;
148
149
0
  avp = new_avp(flags, name, val);
150
0
  if(avp == NULL) {
151
0
    LM_ERR("Failed to create new avp structure\n");
152
0
    return -1;
153
0
  }
154
155
0
  avp->next = *crt_avps;
156
0
  *crt_avps = avp;
157
0
  return 0;
158
0
}
159
160
int add_avp_last(unsigned short flags, int name, int_str val)
161
0
{
162
0
  struct usr_avp* avp;
163
0
  struct usr_avp* last_avp;
164
165
0
  avp = new_avp(flags, name, val);
166
0
  if(avp == NULL) {
167
0
    LM_ERR("Failed to create new avp structure\n");
168
0
    return -1;
169
0
  }
170
171
  /* get end of the list */
172
0
  for( last_avp=*crt_avps ; last_avp && last_avp->next ; last_avp=last_avp->next);
173
174
0
  if (last_avp==NULL) {
175
0
    avp->next = *crt_avps;
176
0
    *crt_avps = last_avp = avp;
177
0
  } else {
178
0
    last_avp->next = avp;
179
0
    avp->next = NULL;
180
0
    last_avp = avp;
181
0
  }
182
0
  return 0;
183
0
}
184
185
struct usr_avp *search_index_avp(unsigned short flags,
186
          int name, int_str *val, unsigned int index)
187
0
{
188
0
  struct usr_avp *avp = NULL;
189
190
0
  while ( (avp=search_first_avp( flags, name, val, avp))!=0 ) {
191
0
    if( index == 0 ){
192
0
      return avp;
193
0
    }
194
0
    index--;
195
0
  }
196
0
  return 0;
197
0
}
198
199
int replace_avp(unsigned short flags, int name, int_str val, int index)
200
0
{
201
0
  struct usr_avp* avp, *avp_prev;
202
0
  struct usr_avp* avp_new, *avp_del;
203
204
0
  if(index < 0) {
205
    /* convert negative index to 0+ */
206
0
    int pidx = count_avps(flags, name) + index;
207
0
    if (pidx < 0) {
208
0
      LM_DBG("AVP with the specified index (%d) not found\n", index);
209
0
      return -1;
210
0
    }
211
212
0
    index = pidx;
213
0
  }
214
215
0
  avp_del = search_index_avp(flags, name, 0, index);
216
0
  if(avp_del == NULL) {
217
0
    LM_DBG("AVP to replace not found\n");
218
0
    return -1;
219
0
  }
220
221
0
  avp_new = new_avp(flags, name, val);
222
0
  if(avp_new == NULL) {
223
0
    LM_ERR("Failed to create new avp structure\n");
224
0
    return -1;
225
0
  }
226
227
0
  for( avp_prev=0,avp=*crt_avps ; avp ; avp_prev=avp,avp=avp->next ) {
228
0
    if (avp==avp_del) {
229
0
      if (avp_prev)
230
0
        avp_prev->next=avp_new;
231
0
      else
232
0
        *crt_avps = avp_new;
233
0
      avp_new->next = avp_del->next;
234
0
      shm_free(avp_del);
235
0
      return 0;
236
0
    }
237
0
  }
238
0
  return 0;
239
0
}
240
241
/* get name functions */
242
static inline str* __get_avp_name(int id, map_t m)
243
0
{
244
0
  map_iterator_t it;
245
0
  int **idp;
246
247
0
  if (map_first(m, &it) < 0) {
248
0
    LM_ERR("map doesn't exist\n");
249
0
    return NULL;
250
0
  }
251
0
  for (;;) {
252
0
    if (!iterator_is_valid(&it))
253
0
      return NULL;
254
255
0
    idp = (int**)iterator_val(&it);
256
0
    if (!idp) {
257
0
      LM_ERR("[BUG] while getting avp name\n");
258
0
      return NULL;
259
0
    }
260
0
    if (p2int(*idp) == id)
261
0
      return iterator_key(&it);
262
0
    if (iterator_next(&it) < 0)
263
0
      return NULL;
264
265
0
  }
266
0
}
267
268
269
inline str* get_avp_name_id(int id)
270
0
{
271
0
  str *name;
272
273
0
  if (id < 0)
274
0
    return NULL;
275
276
0
  name = __get_avp_name(id, avp_map);
277
  /* search extra galiases */
278
0
  if (name)
279
0
    return name;
280
0
  lock_get(extra_lock);
281
0
  name = __get_avp_name(id, avp_map_shm);
282
0
  lock_release(extra_lock);
283
0
  return name;
284
0
}
285
286
inline str* get_avp_name(struct usr_avp *avp)
287
0
{
288
0
  return get_avp_name_id(avp->id);
289
0
}
290
291
/* get value functions */
292
inline void get_avp_val(struct usr_avp *avp, int_str *val)
293
0
{
294
0
  if (avp==0 || val==0)
295
0
    return;
296
297
0
  if (avp->flags & AVP_VAL_STR) {
298
    /* avp type ID, str value */
299
0
    val->s = *(str *)(&avp->data);
300
0
  } else {
301
    /* avp type ID, int value */
302
0
    val->n = (long)(avp->data);
303
0
  }
304
0
}
305
306
307
struct usr_avp** get_avp_list(void)
308
0
{
309
0
  assert( crt_avps!=0 );
310
0
  return crt_avps;
311
0
}
312
313
314
315
316
/* search functions */
317
318
inline static struct usr_avp *internal_search_ID_avp( struct usr_avp *avp,
319
                int id, unsigned short flags)
320
0
{
321
0
  for( ; avp ; avp=avp->next ) {
322
0
    if ( id==avp->id && (flags==0 || (flags&avp->flags))) {
323
0
      return avp;
324
0
    }
325
0
  }
326
0
  return 0;
327
0
}
328
329
330
331
/**
332
 * search first avp beginning with 'start->next'
333
 * if start==NULL, beging from head of avp list
334
 */
335
struct usr_avp *search_first_avp( unsigned short flags,
336
          int id, int_str *val,  struct usr_avp *start)
337
0
{
338
0
  struct usr_avp *head;
339
0
  struct usr_avp *avp;
340
341
0
  if (id < 0) {
342
0
    LM_ERR("invalid avp id %d\n", id);
343
0
    return 0;
344
0
  }
345
346
0
  if(start==0)
347
0
  {
348
0
    assert( crt_avps!=0 );
349
350
0
    if (*crt_avps==0)
351
0
      return 0;
352
0
    head = *crt_avps;
353
0
  } else {
354
0
    if(start->next==0)
355
0
      return 0;
356
0
    head = start->next;
357
0
  }
358
359
  /* search for the AVP by ID (&name) */
360
0
  avp = internal_search_ID_avp(head, id, flags&AVP_SCRIPT_MASK);
361
362
  /* get the value - if required */
363
0
  if (avp && val)
364
0
    get_avp_val(avp, val);
365
366
0
  return avp;
367
0
}
368
369
370
371
struct usr_avp *search_next_avp( struct usr_avp *avp,  int_str *val )
372
0
{
373
0
  if (avp==0 || avp->next==0)
374
0
    return 0;
375
376
0
  avp = internal_search_ID_avp( avp->next, avp->id,
377
0
      avp->flags&AVP_SCRIPT_MASK );
378
379
0
  if (avp && val)
380
0
    get_avp_val(avp, val);
381
382
0
  return avp;
383
0
}
384
385
386
387
/********* free functions ********/
388
389
void destroy_avp( struct usr_avp *avp_del)
390
0
{
391
0
  struct usr_avp *avp;
392
0
  struct usr_avp *avp_prev;
393
394
0
  for( avp_prev=0,avp=*crt_avps ; avp ; avp_prev=avp,avp=avp->next ) {
395
0
    if (avp==avp_del) {
396
0
      if (avp_prev)
397
0
        avp_prev->next=avp->next;
398
0
      else
399
0
        *crt_avps = avp->next;
400
0
      shm_free(avp);
401
0
      return;
402
0
    }
403
0
  }
404
0
}
405
406
int destroy_avps( unsigned short flags, int name, int all)
407
0
{
408
0
  struct usr_avp *avp;
409
0
  int n;
410
411
0
  n = 0;
412
0
  while ( (avp=search_first_avp( flags, name, 0, 0))!=0 ) {
413
0
    destroy_avp( avp );
414
0
    n++;
415
0
    if ( !all )
416
0
      break;
417
0
  }
418
0
  return n;
419
0
}
420
421
void destroy_index_avp( unsigned short flags, int name, int index)
422
0
{
423
0
  struct usr_avp *avp = NULL;
424
425
0
  if(index < 0) {
426
    /* convert negative index to 0+ */
427
0
    int pidx = count_avps(flags, name) + index;
428
0
    if (pidx < 0) {
429
0
      LM_DBG("AVP with the specified index (%d) not found\n", index);
430
0
      return;
431
0
    }
432
433
0
    index = pidx;
434
0
  }
435
436
0
  avp = search_index_avp(flags, name, 0, index);
437
0
  if(avp== NULL) {
438
0
    LM_DBG("AVP with the specified index not found\n");
439
0
    return;
440
0
  }
441
442
0
  destroy_avp( avp );
443
0
}
444
445
int count_avps(unsigned short flags, int name)
446
0
{
447
0
  struct usr_avp *avp = NULL;
448
0
  int n = 0;
449
450
0
  while ((avp=search_first_avp(flags, name, 0, avp)))
451
0
    n++;
452
453
0
  return n;
454
0
}
455
456
void destroy_avp_list_bulk( struct usr_avp **list )
457
0
{
458
0
  struct usr_avp *avp, *foo;
459
460
0
  avp = *list;
461
0
  while( avp ) {
462
0
    foo = avp;
463
0
    avp = avp->next;
464
0
    shm_free_bulk( foo );
465
0
  }
466
0
  *list = 0;
467
0
}
468
469
470
void destroy_avp_list_unsafe( struct usr_avp **list )
471
0
{
472
0
  struct usr_avp *avp, *foo;
473
474
0
  avp = *list;
475
0
  while( avp ) {
476
0
    foo = avp;
477
0
    avp = avp->next;
478
0
    shm_free_unsafe( foo );
479
0
  }
480
0
  *list = 0;
481
0
}
482
483
484
inline void destroy_avp_list( struct usr_avp **list )
485
0
{
486
0
  struct usr_avp *avp, *foo;
487
488
0
  LM_DBG("destroying list %p\n", *list);
489
0
  avp = *list;
490
0
  while( avp ) {
491
0
    foo = avp;
492
0
    avp = avp->next;
493
0
    shm_free( foo );
494
0
  }
495
0
  *list = 0;
496
0
}
497
498
499
void reset_avps(void)
500
0
{
501
0
  assert( crt_avps!=0 );
502
503
0
  if ( crt_avps!=&global_avps) {
504
0
    crt_avps = &global_avps;
505
0
  }
506
0
  destroy_avp_list( crt_avps );
507
0
}
508
509
510
struct usr_avp** set_avp_list( struct usr_avp **list )
511
0
{
512
0
  struct usr_avp **foo;
513
514
0
  assert( crt_avps!=0 );
515
516
0
  foo = crt_avps;
517
0
  crt_avps = list;
518
0
  return foo;
519
0
}
520
521
static inline int __search_avp_map(const str *alias, map_t m)
522
0
{
523
0
  int **id = (int **)map_find(m, *alias);
524
0
  LM_DBG("looking for [%.*s] avp %s - found %d\n", alias->len, alias->s,
525
0
      m == avp_map_shm ? "in shm": "", id ? p2int(*id) : -1);
526
0
  return id ? p2int(*id) : -1;
527
0
}
528
529
530
static int lookup_avp_alias_str(const str *alias, int extra)
531
0
{
532
0
  int id;
533
0
  if (!alias || !alias->len || !alias->s)
534
0
    return -2;
535
536
0
  id = __search_avp_map(alias, avp_map);
537
0
  if (id < 0 && extra) {
538
    /* search extra alias */
539
0
    lock_get(extra_lock);
540
0
    id = __search_avp_map(alias, avp_map_shm);
541
0
    lock_release(extra_lock);
542
0
  }
543
0
  return id;
544
0
}
545
546
static inline int new_avp_alias(const str *alias)
547
0
{
548
0
  int id = last_avp_index + 1;
549
550
0
  if (map_put(avp_map, *alias, int2p(id))) {
551
0
    LM_WARN("[BUG] Value should have already be found [%.*s]\n",
552
0
        alias->len, alias->s);
553
0
    return -1;
554
0
  }
555
  /* successfully added avp */
556
0
  last_avp_index++;
557
558
0
  LM_DBG("added alias %.*s with id %d\n",alias->len,alias->s,id);
559
560
0
  return id;
561
0
}
562
563
static inline int new_avp_extra_alias(const str *alias)
564
0
{
565
0
  int id;
566
567
0
  if (!last_avp_index_shm) {
568
0
    LM_ERR("extra AVPs are not initialized yet\n");
569
0
    return -1;
570
0
  }
571
572
  /* check if last avp is valid */
573
0
  lock_get(extra_lock);
574
0
  id = (*last_avp_index_shm) + 1;
575
0
  if (map_put(avp_map_shm, *alias, int2p(id))) {
576
0
    lock_release(extra_lock);
577
0
    LM_WARN("[BUG] Value should have already be found [%.*s]\n",
578
0
        alias->len, alias->s);
579
0
    return -1;
580
0
  }
581
0
  (*last_avp_index_shm)++;
582
0
  lock_release(extra_lock);
583
584
0
  LM_DBG("added extra alias %.*s with id %d\n",alias->len,alias->s,id);
585
586
0
  return id;
587
0
}
588
589
int parse_avp_spec(const str *name, int *avp_name)
590
0
{
591
0
  int id, extra;
592
593
0
  if (name==0 || name->s==0 || name->len==0)
594
0
    return -1;
595
596
0
  extra = last_avp_index_shm ? 1 : 0;
597
598
0
  if (name->len > 2 && name->s[1] == AVP_NAME_DELIM &&
599
0
      (name->s[0] == 'i' || name->s[0] == 's'))
600
0
    LM_WARN("Deprecated AVP name format \"%.*s\" - use \"%.*s\" instead\n",
601
0
        name->len, name->s, name->len - 2, name->s + 2);
602
603
0
  id = lookup_avp_alias_str(name, extra);
604
0
  if (id < 0) {
605
0
    id = extra ? new_avp_extra_alias(name) : new_avp_alias(name);
606
0
    if (id < 0) {
607
0
      LM_ERR("cannot add new avp\n");
608
0
      return -1;
609
0
    }
610
0
  }
611
0
  if (avp_name)
612
0
    *avp_name = id;
613
0
  return 0;
614
0
}
615
616
int get_avp_id(str *name)
617
0
{
618
0
  int id;
619
0
  if (parse_avp_spec(name, &id)) {
620
0
    LM_ERR("unable to get id\n");
621
0
    return -1;
622
0
  }
623
0
  return id;
624
0
}
625
626
627
struct usr_avp *clone_avp_list(struct usr_avp *old)
628
0
{
629
0
  struct usr_avp *a;
630
0
  int_str val;
631
632
0
  if (!old) return NULL;
633
634
  /* create a copy of the old AVP */
635
0
  get_avp_val( old, &val );
636
0
  a = new_avp( old->flags, old->id, val);
637
0
  if (a==NULL) {
638
0
    LM_ERR("cloning failed, trunking the list\n");
639
0
    return NULL;
640
0
  }
641
642
0
  a->next = clone_avp_list(old->next);
643
0
  return a;
644
0
}
645
646
647
struct usr_avp** set_bavp_list(struct usr_avp **list)
648
0
{
649
0
  struct usr_avp **foo;
650
651
0
  foo = crt_bavps;
652
0
  crt_bavps = list;
653
0
  return foo;
654
0
}
655
656
struct usr_avp** get_bavp_list(void)
657
0
{
658
0
  return crt_bavps;
659
0
}
660
661
struct usr_avp** reset_bavp_list(void)
662
0
{
663
0
  return set_bavp_list(NULL);
664
0
}