/src/kamailio/src/core/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 Kamailio, a free SIP server. |
5 | | * |
6 | | * Kamailio 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 | | * Kamailio 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 | | */ |
21 | | |
22 | | |
23 | | /*! |
24 | | * \file |
25 | | * \brief Kamailio core :: Attribute value pair handling (AVP) |
26 | | * \ingroup core |
27 | | * Module: \ref core |
28 | | */ |
29 | | |
30 | | #include <assert.h> |
31 | | #include <ctype.h> |
32 | | #include <string.h> |
33 | | #include <stdlib.h> |
34 | | |
35 | | #include <stdio.h> |
36 | | |
37 | | #include "sr_module.h" |
38 | | #include "dprint.h" |
39 | | #include "str.h" |
40 | | #include "ut.h" |
41 | | #include "mem/shm_mem.h" |
42 | | #include "mem/mem.h" |
43 | | #include "usr_avp.h" |
44 | | |
45 | | enum idx |
46 | | { |
47 | | IDX_FROM_URI = 0, |
48 | | IDX_TO_URI, |
49 | | IDX_FROM_USER, |
50 | | IDX_TO_USER, |
51 | | IDX_FROM_DOMAIN, |
52 | | IDX_TO_DOMAIN, |
53 | | IDX_MAX |
54 | | }; |
55 | | |
56 | | |
57 | | struct avp_galias |
58 | | { |
59 | | str alias; |
60 | | struct avp_spec avp; |
61 | | struct avp_galias *next; |
62 | | }; |
63 | | |
64 | | static struct avp_galias *galiases = 0; |
65 | | |
66 | | static avp_list_t def_list[IDX_MAX]; /* Default AVP lists */ |
67 | | static avp_list_t *crt_list[IDX_MAX]; /* Pointer to current AVP lists */ |
68 | | |
69 | | /* Global AVP related variables go to shm mem */ |
70 | | static avp_list_t *def_glist; |
71 | | static avp_list_t **crt_glist; |
72 | | |
73 | | /* AVP flags */ |
74 | | int registered_avpflags_no = 0; |
75 | | static char *registered_avpflags[MAX_AVPFLAG]; |
76 | | |
77 | | /* Initialize AVP lists in private memory and allocate memory |
78 | | * for shared lists |
79 | | */ |
80 | | int init_avps(void) |
81 | 0 | { |
82 | 0 | int i; |
83 | | /* Empty default lists */ |
84 | 0 | memset(def_list, 0, sizeof(avp_list_t) * IDX_MAX); |
85 | | |
86 | | /* Point current pointers to default lists */ |
87 | 0 | for(i = 0; i < IDX_MAX; i++) { |
88 | 0 | crt_list[i] = &def_list[i]; |
89 | 0 | } |
90 | |
|
91 | 0 | def_glist = (avp_list_t *)shm_malloc(sizeof(avp_list_t)); |
92 | 0 | crt_glist = (avp_list_t **)shm_malloc(sizeof(avp_list_t *)); |
93 | 0 | if(!def_glist || !crt_glist) { |
94 | 0 | SHM_MEM_ERROR; |
95 | 0 | return -1; |
96 | 0 | } |
97 | 0 | *def_glist = 0; |
98 | 0 | *crt_glist = def_glist; |
99 | 0 | return 0; |
100 | 0 | } |
101 | | |
102 | | |
103 | | /* |
104 | | * Select active AVP list based on the value of flags |
105 | | */ |
106 | | static avp_list_t *select_list(avp_flags_t flags) |
107 | 0 | { |
108 | 0 | if(flags & AVP_CLASS_URI) { |
109 | 0 | if(flags & AVP_TRACK_TO) { |
110 | 0 | return crt_list[IDX_TO_URI]; |
111 | 0 | } else { |
112 | 0 | return crt_list[IDX_FROM_URI]; |
113 | 0 | } |
114 | 0 | } else if(flags & AVP_CLASS_USER) { |
115 | 0 | if(flags & AVP_TRACK_TO) { |
116 | 0 | return crt_list[IDX_TO_USER]; |
117 | 0 | } else { |
118 | 0 | return crt_list[IDX_FROM_USER]; |
119 | 0 | } |
120 | 0 | } else if(flags & AVP_CLASS_DOMAIN) { |
121 | 0 | if(flags & AVP_TRACK_TO) { |
122 | 0 | return crt_list[IDX_TO_DOMAIN]; |
123 | 0 | } else { |
124 | 0 | return crt_list[IDX_FROM_DOMAIN]; |
125 | 0 | } |
126 | 0 | } else if(flags & AVP_CLASS_GLOBAL) { |
127 | 0 | return *crt_glist; |
128 | 0 | } |
129 | | |
130 | 0 | return NULL; |
131 | 0 | } |
132 | | |
133 | | inline static avp_id_t compute_ID(str *name) |
134 | 0 | { |
135 | 0 | char *p; |
136 | 0 | avp_id_t id; |
137 | |
|
138 | 0 | id = 0; |
139 | 0 | for(p = name->s + name->len - 1; p >= name->s; p--) |
140 | 0 | id ^= *p; |
141 | 0 | return id; |
142 | 0 | } |
143 | | |
144 | | |
145 | | avp_t *create_avp(avp_flags_t flags, avp_name_t name, avp_value_t val) |
146 | 0 | { |
147 | 0 | avp_t *avp; |
148 | 0 | str *s; |
149 | 0 | struct str_num_data *sid; |
150 | 0 | struct str_str_data *ssd; |
151 | 0 | int len; |
152 | | |
153 | | /* compute the required mem size */ |
154 | 0 | len = sizeof(struct usr_avp); |
155 | 0 | if(flags & AVP_NAME_STR) { |
156 | 0 | if(name.s.s == 0 || name.s.len == 0) { |
157 | 0 | LM_ERR("NULL or EMPTY NAME AVP!"); |
158 | 0 | goto error; |
159 | 0 | } |
160 | 0 | if(flags & AVP_VAL_STR) { |
161 | 0 | len += sizeof(struct str_str_data) - sizeof(union usr_avp_data) |
162 | 0 | + name.s.len + 1 /* Terminating zero for regex search */ |
163 | 0 | + val.s.len + 1; /* Value is zero terminated */ |
164 | 0 | } else { |
165 | 0 | len += sizeof(struct str_num_data) - sizeof(union usr_avp_data) |
166 | 0 | + name.s.len + 1; /* Terminating zero for regex search */ |
167 | 0 | } |
168 | 0 | } else { |
169 | 0 | if(name.n == 0) { |
170 | 0 | LM_ERR("0 ID AVP!"); |
171 | 0 | goto error; |
172 | 0 | } |
173 | 0 | if(flags & AVP_VAL_STR) { |
174 | 0 | len += sizeof(str) - sizeof(union usr_avp_data) + val.s.len + 1; |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | 0 | avp = (struct usr_avp *)shm_malloc(len); |
179 | 0 | if(avp == 0) { |
180 | 0 | SHM_MEM_ERROR; |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | 0 | avp->flags = flags; |
185 | 0 | avp->id = (flags & AVP_NAME_STR) ? compute_ID(&name.s) : name.n; |
186 | 0 | avp->next = NULL; |
187 | |
|
188 | 0 | switch(flags & (AVP_NAME_STR | AVP_VAL_STR)) { |
189 | 0 | case 0: |
190 | | /* avp type ID, int value */ |
191 | 0 | avp->d.l = val.n; |
192 | 0 | break; |
193 | 0 | case AVP_NAME_STR: |
194 | | /* avp type str, int value */ |
195 | 0 | sid = (struct str_num_data *)&avp->d.data[0]; |
196 | 0 | sid->val = val.n; |
197 | 0 | sid->name.len = name.s.len; |
198 | 0 | sid->name.s = (char *)sid + sizeof(struct str_num_data); |
199 | 0 | memcpy(sid->name.s, name.s.s, name.s.len); |
200 | 0 | sid->name.s[name.s.len] = '\0'; /* Zero terminator */ |
201 | 0 | break; |
202 | 0 | case AVP_VAL_STR: |
203 | | /* avp type ID, str value */ |
204 | 0 | s = (str *)&avp->d.data[0]; |
205 | 0 | s->len = val.s.len; |
206 | 0 | s->s = (char *)s + sizeof(str); |
207 | 0 | memcpy(s->s, val.s.s, s->len); |
208 | 0 | s->s[s->len] = 0; |
209 | 0 | break; |
210 | 0 | case AVP_NAME_STR | AVP_VAL_STR: |
211 | | /* avp type str, str value */ |
212 | 0 | ssd = (struct str_str_data *)&avp->d.data[0]; |
213 | 0 | ssd->name.len = name.s.len; |
214 | 0 | ssd->name.s = (char *)ssd + sizeof(struct str_str_data); |
215 | 0 | memcpy(ssd->name.s, name.s.s, name.s.len); |
216 | 0 | ssd->name.s[name.s.len] = '\0'; /* Zero terminator */ |
217 | 0 | ssd->val.len = val.s.len; |
218 | 0 | ssd->val.s = ssd->name.s + ssd->name.len + 1; |
219 | 0 | memcpy(ssd->val.s, val.s.s, val.s.len); |
220 | 0 | ssd->val.s[ssd->val.len] = 0; |
221 | 0 | break; |
222 | 0 | } |
223 | 0 | return avp; |
224 | 0 | error: |
225 | 0 | return 0; |
226 | 0 | } |
227 | | |
228 | | int add_avp_list( |
229 | | avp_list_t *list, avp_flags_t flags, avp_name_t name, avp_value_t val) |
230 | 0 | { |
231 | 0 | avp_t *avp; |
232 | |
|
233 | 0 | assert(list != 0); |
234 | | |
235 | 0 | if((avp = create_avp(flags, name, val))) { |
236 | 0 | avp->next = *list; |
237 | 0 | *list = avp; |
238 | 0 | return 0; |
239 | 0 | } |
240 | | |
241 | 0 | return -1; |
242 | 0 | } |
243 | | |
244 | | |
245 | | int add_avp(avp_flags_t flags, avp_name_t name, avp_value_t val) |
246 | 0 | { |
247 | 0 | avp_flags_t avp_class; |
248 | 0 | avp_list_t *list; |
249 | | |
250 | | /* Add avp to uri class if no class has been |
251 | | * specified by the caller |
252 | | */ |
253 | 0 | if((flags & AVP_CLASS_ALL) == 0) |
254 | 0 | flags |= AVP_CLASS_URI; |
255 | 0 | if((flags & AVP_TRACK_ALL) == 0) |
256 | 0 | flags |= AVP_TRACK_FROM; |
257 | 0 | if(!(list = select_list(flags))) |
258 | 0 | return -1; |
259 | | |
260 | 0 | if(flags & AVP_CLASS_URI) |
261 | 0 | avp_class = AVP_CLASS_URI; |
262 | 0 | else if(flags & AVP_CLASS_USER) |
263 | 0 | avp_class = AVP_CLASS_USER; |
264 | 0 | else if(flags & AVP_CLASS_DOMAIN) |
265 | 0 | avp_class = AVP_CLASS_DOMAIN; |
266 | 0 | else |
267 | 0 | avp_class = AVP_CLASS_GLOBAL; |
268 | | |
269 | | /* Make that only the selected class is set |
270 | | * if the caller set more classes in flags |
271 | | */ |
272 | 0 | return add_avp_list( |
273 | 0 | list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val); |
274 | 0 | } |
275 | | |
276 | | int add_avp_before( |
277 | | avp_t *avp, avp_flags_t flags, avp_name_t name, avp_value_t val) |
278 | 0 | { |
279 | 0 | avp_t *new_avp; |
280 | |
|
281 | 0 | if(!avp) { |
282 | 0 | return add_avp(flags, name, val); |
283 | 0 | } |
284 | | |
285 | 0 | if((flags & AVP_CLASS_ALL) == 0) |
286 | 0 | flags |= (avp->flags & AVP_CLASS_ALL); |
287 | 0 | if((flags & AVP_TRACK_ALL) == 0) |
288 | 0 | flags |= (avp->flags & AVP_TRACK_ALL); |
289 | |
|
290 | 0 | if((avp->flags & (AVP_CLASS_ALL | AVP_TRACK_ALL)) |
291 | 0 | != (flags & (AVP_CLASS_ALL | AVP_TRACK_ALL))) { |
292 | 0 | LM_ERR("Source and target AVPs have different CLASS/TRACK\n"); |
293 | 0 | return -1; |
294 | 0 | } |
295 | 0 | if((new_avp = create_avp(flags, name, val))) { |
296 | 0 | new_avp->next = avp->next; |
297 | 0 | avp->next = new_avp; |
298 | 0 | return 0; |
299 | 0 | } |
300 | 0 | return -1; |
301 | 0 | } |
302 | | |
303 | | /* get value functions */ |
304 | | inline str *get_avp_name(avp_t *avp) |
305 | 0 | { |
306 | 0 | struct str_num_data *sid; |
307 | 0 | struct str_str_data *ssd; |
308 | |
|
309 | 0 | switch(avp->flags & (AVP_NAME_STR | AVP_VAL_STR)) { |
310 | 0 | case 0: |
311 | | /* avp type ID, int value */ |
312 | 0 | case AVP_VAL_STR: |
313 | | /* avp type ID, str value */ |
314 | 0 | return 0; |
315 | 0 | case AVP_NAME_STR: |
316 | | /* avp type str, int value */ |
317 | 0 | sid = (struct str_num_data *)&avp->d.data[0]; |
318 | 0 | return &sid->name; |
319 | 0 | case AVP_NAME_STR | AVP_VAL_STR: |
320 | | /* avp type str, str value */ |
321 | 0 | ssd = (struct str_str_data *)&avp->d.data[0]; |
322 | 0 | return &ssd->name; |
323 | 0 | } |
324 | | |
325 | 0 | LM_ERR("unknown avp type (name&val) %d\n", |
326 | 0 | avp->flags & (AVP_NAME_STR | AVP_VAL_STR)); |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | | |
331 | | inline void get_avp_val(avp_t *avp, avp_value_t *val) |
332 | 0 | { |
333 | 0 | str *s; |
334 | 0 | struct str_num_data *sid; |
335 | 0 | struct str_str_data *ssd; |
336 | |
|
337 | 0 | if(avp == 0 || val == 0) |
338 | 0 | return; |
339 | | |
340 | 0 | switch(avp->flags & (AVP_NAME_STR | AVP_VAL_STR)) { |
341 | 0 | case 0: |
342 | | /* avp type ID, int value */ |
343 | 0 | val->n = avp->d.l; |
344 | 0 | break; |
345 | 0 | case AVP_NAME_STR: |
346 | | /* avp type str, int value */ |
347 | 0 | sid = (struct str_num_data *)&avp->d.data[0]; |
348 | 0 | val->n = sid->val; |
349 | 0 | break; |
350 | 0 | case AVP_VAL_STR: |
351 | | /* avp type ID, str value */ |
352 | 0 | s = (str *)&avp->d.data[0]; |
353 | 0 | val->s = *s; |
354 | 0 | break; |
355 | 0 | case AVP_NAME_STR | AVP_VAL_STR: |
356 | | /* avp type str, str value */ |
357 | 0 | ssd = (struct str_str_data *)&avp->d.data[0]; |
358 | 0 | val->s = ssd->val; |
359 | 0 | break; |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | | |
364 | | /* Return the current list of user attributes */ |
365 | | avp_list_t get_avp_list(avp_flags_t flags) |
366 | 0 | { |
367 | 0 | avp_list_t *list; |
368 | |
|
369 | 0 | list = select_list(flags); |
370 | 0 | return (list ? *list : NULL); |
371 | 0 | } |
372 | | |
373 | | |
374 | | /* |
375 | | * Compare given id with id in avp, return true if they match |
376 | | */ |
377 | | static inline int match_by_id(avp_t *avp, avp_id_t id) |
378 | 0 | { |
379 | 0 | if(avp->id == id && (avp->flags & AVP_NAME_STR) == 0) { |
380 | 0 | return 1; |
381 | 0 | } |
382 | 0 | return 0; |
383 | 0 | } |
384 | | |
385 | | |
386 | | /* |
387 | | * Compare given name with name in avp, return true if they are same |
388 | | */ |
389 | | static inline int match_by_name(avp_t *avp, avp_id_t id, str *name) |
390 | 0 | { |
391 | 0 | str *avp_name; |
392 | 0 | if(id == avp->id && avp->flags & AVP_NAME_STR |
393 | 0 | && (avp_name = get_avp_name(avp)) != 0 && avp_name->len == name->len |
394 | 0 | && !strncasecmp(avp_name->s, name->s, name->len)) { |
395 | 0 | return 1; |
396 | 0 | } |
397 | 0 | return 0; |
398 | 0 | } |
399 | | |
400 | | |
401 | | /* |
402 | | * Compare name with name in AVP using regular expressions, return |
403 | | * true if they match |
404 | | */ |
405 | | static inline int match_by_re(avp_t *avp, regex_t *re) |
406 | 0 | { |
407 | 0 | regmatch_t pmatch; |
408 | 0 | str *avp_name; |
409 | | /* AVP identifiable by name ? */ |
410 | 0 | if(!(avp->flags & AVP_NAME_STR)) |
411 | 0 | return 0; |
412 | 0 | if((avp_name = get_avp_name(avp)) == 0) /* valid AVP name ? */ |
413 | 0 | return 0; |
414 | 0 | if(!avp_name->s) /* AVP name validation */ |
415 | 0 | return 0; |
416 | 0 | if(regexec(re, avp_name->s, 1, &pmatch, 0) == 0) { /* re match ? */ |
417 | 0 | return 1; |
418 | 0 | } |
419 | 0 | return 0; |
420 | 0 | } |
421 | | |
422 | | |
423 | | avp_t *search_first_avp(avp_flags_t flags, avp_name_t name, avp_value_t *val, |
424 | | struct search_state *s) |
425 | 0 | { |
426 | 0 | avp_ident_t id; |
427 | 0 | id.flags = flags; |
428 | 0 | id.name = name; |
429 | 0 | id.index = 0; |
430 | 0 | return search_avp(id, val, s); |
431 | 0 | } |
432 | | |
433 | | avp_t *search_avp( |
434 | | avp_ident_t ident, avp_value_t *val, struct search_state *state) |
435 | 0 | { |
436 | 0 | avp_t *ret; |
437 | 0 | static struct search_state st; |
438 | 0 | avp_list_t *list; |
439 | |
|
440 | 0 | if(ident.name.s.s == 0 && ident.name.s.len == 0) { |
441 | 0 | LM_ERR("0 ID or NULL NAME AVP!"); |
442 | 0 | return 0; |
443 | 0 | } |
444 | | |
445 | 0 | switch(ident.flags & AVP_INDEX_ALL) { |
446 | 0 | case AVP_INDEX_BACKWARD: |
447 | 0 | case AVP_INDEX_FORWARD: |
448 | 0 | WARN("AVP specified with index, but not used for search\n"); |
449 | 0 | break; |
450 | 0 | } |
451 | | |
452 | 0 | if(!state) { |
453 | 0 | memset(&st, 0, sizeof(struct search_state)); |
454 | 0 | state = &st; |
455 | 0 | } |
456 | |
|
457 | 0 | if((ident.flags & AVP_CLASS_ALL) == 0) { |
458 | | /* The caller did not specify any class to search in, so enable |
459 | | * all of them by default |
460 | | */ |
461 | 0 | ident.flags |= AVP_CLASS_ALL; |
462 | |
|
463 | 0 | if((ident.flags & AVP_TRACK_ALL) == 0) { |
464 | | /* The caller did not specify even the track to search in, so search |
465 | | * in the track_from |
466 | | */ |
467 | 0 | ident.flags |= AVP_TRACK_FROM; |
468 | 0 | } |
469 | 0 | } |
470 | |
|
471 | 0 | if(!(list = select_list(ident.flags))) |
472 | 0 | return NULL; |
473 | | |
474 | 0 | state->flags = ident.flags; |
475 | 0 | state->avp = *list; |
476 | 0 | state->name = ident.name; |
477 | |
|
478 | 0 | if(ident.flags & AVP_NAME_STR) { |
479 | 0 | state->id = compute_ID(&ident.name.s); |
480 | 0 | } |
481 | |
|
482 | 0 | ret = search_next_avp(state, val); |
483 | | |
484 | | /* Make sure that search next avp stays in the same class as the first |
485 | | * avp found */ |
486 | 0 | if(ret) { |
487 | 0 | state->flags = |
488 | 0 | (ident.flags & ~AVP_CLASS_ALL) | (ret->flags & AVP_CLASS_ALL); |
489 | 0 | } |
490 | 0 | return ret; |
491 | 0 | } |
492 | | |
493 | | avp_t *search_next_avp(struct search_state *s, avp_value_t *val) |
494 | 0 | { |
495 | 0 | int matched; |
496 | 0 | avp_t *avp; |
497 | 0 | avp_list_t *list; |
498 | |
|
499 | 0 | if(s == 0) { |
500 | 0 | LM_ERR("Invalid parameter value\n"); |
501 | 0 | return 0; |
502 | 0 | } |
503 | | |
504 | 0 | switch(s->flags & AVP_INDEX_ALL) { |
505 | 0 | case AVP_INDEX_BACKWARD: |
506 | 0 | case AVP_INDEX_FORWARD: |
507 | 0 | WARN("AVP specified with index, but not used for search\n"); |
508 | 0 | break; |
509 | 0 | } |
510 | | |
511 | 0 | while(1) { |
512 | 0 | for(; s->avp; s->avp = s->avp->next) { |
513 | 0 | if(s->flags & AVP_NAME_RE) { |
514 | 0 | matched = match_by_re(s->avp, s->name.re); |
515 | 0 | } else if(s->flags & AVP_NAME_STR) { |
516 | 0 | matched = match_by_name(s->avp, s->id, &s->name.s); |
517 | 0 | } else { |
518 | 0 | matched = match_by_id(s->avp, s->name.n); |
519 | 0 | } |
520 | 0 | if(matched) { |
521 | 0 | avp = s->avp; |
522 | 0 | s->avp = s->avp->next; |
523 | 0 | if(val) |
524 | 0 | get_avp_val(avp, val); |
525 | 0 | return avp; |
526 | 0 | } |
527 | 0 | } |
528 | | |
529 | 0 | if(s->flags & AVP_CLASS_URI) { |
530 | 0 | s->flags &= ~AVP_CLASS_URI; |
531 | 0 | list = select_list(s->flags); |
532 | 0 | } else if(s->flags & AVP_CLASS_USER) { |
533 | 0 | s->flags &= ~AVP_CLASS_USER; |
534 | 0 | list = select_list(s->flags); |
535 | 0 | } else if(s->flags & AVP_CLASS_DOMAIN) { |
536 | 0 | s->flags &= ~AVP_CLASS_DOMAIN; |
537 | 0 | list = select_list(s->flags); |
538 | 0 | } else { |
539 | 0 | s->flags &= ~AVP_CLASS_GLOBAL; |
540 | 0 | return 0; |
541 | 0 | } |
542 | 0 | if(!list) |
543 | 0 | return 0; |
544 | 0 | s->avp = *list; |
545 | 0 | } |
546 | | |
547 | 0 | return 0; |
548 | 0 | } |
549 | | |
550 | | int search_reverse( |
551 | | avp_t *cur, struct search_state *st, avp_index_t index, avp_list_t *ret) |
552 | 0 | { |
553 | 0 | avp_index_t lvl; |
554 | |
|
555 | 0 | if(!cur) |
556 | 0 | return 0; |
557 | 0 | lvl = search_reverse(search_next_avp(st, NULL), st, index, ret) + 1; |
558 | 0 | if(index == lvl) |
559 | 0 | *ret = cur; |
560 | 0 | return lvl; |
561 | 0 | } |
562 | | |
563 | | avp_t *search_avp_by_index( |
564 | | avp_flags_t flags, avp_name_t name, avp_value_t *val, avp_index_t index) |
565 | 0 | { |
566 | 0 | avp_t *ret, *cur; |
567 | 0 | struct search_state st; |
568 | |
|
569 | 0 | if(flags & AVP_NAME_RE) { |
570 | 0 | BUG("search_by_index not supported for AVP_NAME_RE\n"); |
571 | 0 | return 0; |
572 | 0 | } |
573 | 0 | switch(flags & AVP_INDEX_ALL) { |
574 | 0 | case 0: |
575 | 0 | ret = search_first_avp(flags, name, val, &st); |
576 | 0 | if(!ret || search_next_avp(&st, NULL)) |
577 | 0 | return 0; |
578 | 0 | else |
579 | 0 | return ret; |
580 | 0 | case AVP_INDEX_ALL: |
581 | 0 | BUG("search_by_index not supported for anonymous index []\n"); |
582 | 0 | return 0; |
583 | 0 | case AVP_INDEX_FORWARD: |
584 | 0 | ret = NULL; |
585 | 0 | cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st); |
586 | 0 | search_reverse(cur, &st, index, &ret); |
587 | 0 | if(ret && val) |
588 | 0 | get_avp_val(ret, val); |
589 | 0 | return ret; |
590 | 0 | case AVP_INDEX_BACKWARD: |
591 | 0 | ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st); |
592 | 0 | for(index--; (ret && index); |
593 | 0 | ret = search_next_avp(&st, val), index--) |
594 | 0 | ; |
595 | 0 | return ret; |
596 | 0 | } |
597 | | |
598 | 0 | return 0; |
599 | 0 | } |
600 | | |
601 | | /********* free functions ********/ |
602 | | void destroy_avp(avp_t *avp_del) |
603 | 0 | { |
604 | 0 | int i; |
605 | 0 | avp_t *avp, *avp_prev; |
606 | |
|
607 | 0 | for(i = 0; i < IDX_MAX; i++) { |
608 | 0 | for(avp_prev = 0, avp = *crt_list[i]; avp; |
609 | 0 | avp_prev = avp, avp = avp->next) { |
610 | 0 | if(avp == avp_del) { |
611 | 0 | if(avp_prev) { |
612 | 0 | avp_prev->next = avp->next; |
613 | 0 | } else { |
614 | 0 | *crt_list[i] = avp->next; |
615 | 0 | } |
616 | 0 | shm_free(avp); |
617 | 0 | return; |
618 | 0 | } |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | 0 | for(avp_prev = 0, avp = **crt_glist; avp; avp_prev = avp, avp = avp->next) { |
623 | 0 | if(avp == avp_del) { |
624 | 0 | if(avp_prev) { |
625 | 0 | avp_prev->next = avp->next; |
626 | 0 | } else { |
627 | 0 | **crt_glist = avp->next; |
628 | 0 | } |
629 | 0 | shm_free(avp); |
630 | 0 | return; |
631 | 0 | } |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | |
636 | | void destroy_avp_list_unsafe(avp_list_t *list) |
637 | 0 | { |
638 | 0 | avp_t *avp, *foo; |
639 | |
|
640 | 0 | avp = *list; |
641 | 0 | while(avp) { |
642 | 0 | foo = avp; |
643 | 0 | avp = avp->next; |
644 | 0 | shm_free_unsafe(foo); |
645 | 0 | } |
646 | 0 | *list = 0; |
647 | 0 | } |
648 | | |
649 | | |
650 | | inline void destroy_avp_list(avp_list_t *list) |
651 | 0 | { |
652 | 0 | avp_t *avp, *foo; |
653 | |
|
654 | 0 | LM_DBG("destroying list %p\n", *list); |
655 | 0 | avp = *list; |
656 | 0 | while(avp) { |
657 | 0 | foo = avp; |
658 | 0 | avp = avp->next; |
659 | 0 | shm_free(foo); |
660 | 0 | } |
661 | 0 | *list = 0; |
662 | 0 | } |
663 | | |
664 | | int reset_avp_list(int flags) |
665 | 0 | { |
666 | 0 | int i; |
667 | 0 | if(flags & AVP_CLASS_URI) { |
668 | 0 | if(flags & AVP_TRACK_FROM) |
669 | 0 | i = IDX_FROM_URI; |
670 | 0 | else |
671 | 0 | i = IDX_TO_URI; |
672 | 0 | } else if(flags & AVP_CLASS_USER) { |
673 | 0 | if(flags & AVP_TRACK_FROM) |
674 | 0 | i = IDX_FROM_USER; |
675 | 0 | else |
676 | 0 | i = IDX_TO_USER; |
677 | 0 | } else if(flags & AVP_CLASS_DOMAIN) { |
678 | 0 | if(flags & AVP_TRACK_FROM) |
679 | 0 | i = IDX_FROM_DOMAIN; |
680 | 0 | else |
681 | 0 | i = IDX_TO_DOMAIN; |
682 | 0 | } else |
683 | 0 | return -1; |
684 | | |
685 | 0 | crt_list[i] = &def_list[i]; |
686 | 0 | destroy_avp_list(crt_list[i]); |
687 | 0 | return 0; |
688 | 0 | } |
689 | | |
690 | | void reset_avps(void) |
691 | 0 | { |
692 | 0 | int i; |
693 | 0 | for(i = 0; i < IDX_MAX; i++) { |
694 | 0 | crt_list[i] = &def_list[i]; |
695 | 0 | destroy_avp_list(crt_list[i]); |
696 | 0 | } |
697 | 0 | } |
698 | | |
699 | | |
700 | | avp_list_t *set_avp_list(avp_flags_t flags, avp_list_t *list) |
701 | 0 | { |
702 | 0 | avp_list_t *prev; |
703 | |
|
704 | 0 | if(flags & AVP_CLASS_URI) { |
705 | 0 | if(flags & AVP_TRACK_FROM) { |
706 | 0 | prev = crt_list[IDX_FROM_URI]; |
707 | 0 | crt_list[IDX_FROM_URI] = list; |
708 | 0 | } else { |
709 | 0 | prev = crt_list[IDX_TO_URI]; |
710 | 0 | crt_list[IDX_TO_URI] = list; |
711 | 0 | } |
712 | 0 | } else if(flags & AVP_CLASS_USER) { |
713 | 0 | if(flags & AVP_TRACK_FROM) { |
714 | 0 | prev = crt_list[IDX_FROM_USER]; |
715 | 0 | crt_list[IDX_FROM_USER] = list; |
716 | 0 | } else { |
717 | 0 | prev = crt_list[IDX_TO_USER]; |
718 | 0 | crt_list[IDX_TO_USER] = list; |
719 | 0 | } |
720 | 0 | } else if(flags & AVP_CLASS_DOMAIN) { |
721 | 0 | if(flags & AVP_TRACK_FROM) { |
722 | 0 | prev = crt_list[IDX_FROM_DOMAIN]; |
723 | 0 | crt_list[IDX_FROM_DOMAIN] = list; |
724 | 0 | } else { |
725 | 0 | prev = crt_list[IDX_TO_DOMAIN]; |
726 | 0 | crt_list[IDX_TO_DOMAIN] = list; |
727 | 0 | } |
728 | 0 | } else { |
729 | 0 | prev = *crt_glist; |
730 | 0 | *crt_glist = list; |
731 | 0 | } |
732 | |
|
733 | 0 | return prev; |
734 | 0 | } |
735 | | |
736 | | |
737 | | /********* global aliases functions ********/ |
738 | | |
739 | | static inline int check_avp_galias(str *alias, int type, numstr_ut avp_name) |
740 | 0 | { |
741 | 0 | struct avp_galias *ga; |
742 | |
|
743 | 0 | type &= AVP_NAME_STR; |
744 | |
|
745 | 0 | for(ga = galiases; ga; ga = ga->next) { |
746 | | /* check for duplicated alias names */ |
747 | 0 | if(alias->len == ga->alias.len |
748 | 0 | && (strncasecmp(alias->s, ga->alias.s, alias->len) == 0)) |
749 | 0 | return -1; |
750 | | /*check for duplicated avp names */ |
751 | 0 | if(type == ga->avp.type) { |
752 | 0 | if(type & AVP_NAME_STR) { |
753 | 0 | if(avp_name.s.len == ga->avp.name.s.len |
754 | 0 | && (strncasecmp(avp_name.s.s, ga->avp.name.s.s, |
755 | 0 | avp_name.s.len) |
756 | 0 | == 0)) |
757 | 0 | return -1; |
758 | 0 | } else { |
759 | 0 | if(avp_name.n == ga->avp.name.n) |
760 | 0 | return -1; |
761 | 0 | } |
762 | 0 | } |
763 | 0 | } |
764 | 0 | return 0; |
765 | 0 | } |
766 | | |
767 | | |
768 | | int add_avp_galias(str *alias, int type, numstr_ut avp_name) |
769 | 0 | { |
770 | 0 | struct avp_galias *ga; |
771 | |
|
772 | 0 | if((type & AVP_NAME_STR && (!avp_name.s.s || !avp_name.s.len)) || !alias |
773 | 0 | || !alias->s || !alias->len) { |
774 | 0 | LM_ERR("null params received\n"); |
775 | 0 | goto error; |
776 | 0 | } |
777 | | |
778 | 0 | if(check_avp_galias(alias, type, avp_name) != 0) { |
779 | 0 | LM_ERR("duplicate alias/avp entry\n"); |
780 | 0 | goto error; |
781 | 0 | } |
782 | | |
783 | 0 | ga = (struct avp_galias *)pkg_malloc(sizeof(struct avp_galias)); |
784 | 0 | if(ga == 0) { |
785 | 0 | PKG_MEM_ERROR; |
786 | 0 | goto error; |
787 | 0 | } |
788 | | |
789 | 0 | ga->alias.s = (char *)pkg_malloc(alias->len + 1); |
790 | 0 | if(ga->alias.s == 0) { |
791 | 0 | PKG_MEM_ERROR; |
792 | 0 | goto error1; |
793 | 0 | } |
794 | 0 | memcpy(ga->alias.s, alias->s, alias->len); |
795 | 0 | ga->alias.len = alias->len; |
796 | |
|
797 | 0 | ga->avp.type = type & AVP_NAME_STR; |
798 | |
|
799 | 0 | if(type & AVP_NAME_STR) { |
800 | 0 | ga->avp.name.s.s = (char *)pkg_malloc(avp_name.s.len + 1); |
801 | 0 | if(ga->avp.name.s.s == 0) { |
802 | 0 | PKG_MEM_ERROR; |
803 | 0 | goto error2; |
804 | 0 | } |
805 | 0 | ga->avp.name.s.len = avp_name.s.len; |
806 | 0 | memcpy(ga->avp.name.s.s, avp_name.s.s, avp_name.s.len); |
807 | 0 | ga->avp.name.s.s[avp_name.s.len] = 0; |
808 | 0 | LM_DBG("registering <%s> for avp name <%s>\n", ga->alias.s, |
809 | 0 | ga->avp.name.s.s); |
810 | 0 | } else { |
811 | 0 | ga->avp.name.n = avp_name.n; |
812 | 0 | LM_DBG("registering <%s> for avp id <%ld>\n", ga->alias.s, |
813 | 0 | ga->avp.name.n); |
814 | 0 | } |
815 | | |
816 | 0 | ga->next = galiases; |
817 | 0 | galiases = ga; |
818 | |
|
819 | 0 | return 0; |
820 | 0 | error2: |
821 | 0 | pkg_free(ga->alias.s); |
822 | 0 | error1: |
823 | 0 | pkg_free(ga); |
824 | 0 | error: |
825 | 0 | return -1; |
826 | 0 | } |
827 | | |
828 | | |
829 | | int lookup_avp_galias(str *alias, int *type, numstr_ut *avp_name) |
830 | 0 | { |
831 | 0 | struct avp_galias *ga; |
832 | |
|
833 | 0 | for(ga = galiases; ga; ga = ga->next) |
834 | 0 | if(alias->len == ga->alias.len |
835 | 0 | && (strncasecmp(alias->s, ga->alias.s, alias->len) == 0)) { |
836 | 0 | *type = ga->avp.type; |
837 | 0 | *avp_name = ga->avp.name; |
838 | 0 | return 0; |
839 | 0 | } |
840 | | |
841 | 0 | return -1; |
842 | 0 | } |
843 | | |
844 | | |
845 | | /* parsing functions */ |
846 | | #define ERR_IF_CONTAINS(name, chr) \ |
847 | 0 | if(memchr(name->s, chr, name->len)) { \ |
848 | 0 | LM_ERR("Unexpected control character '%c' in AVP name\n", chr); \ |
849 | 0 | goto error; \ |
850 | 0 | } |
851 | | |
852 | | int parse_avp_name(str *name, int *type, numstr_ut *avp_name, int *index) |
853 | 0 | { |
854 | 0 | int ret; |
855 | 0 | avp_ident_t attr; |
856 | |
|
857 | 0 | ret = parse_avp_ident(name, &attr); |
858 | 0 | if(!ret) { |
859 | 0 | if(type) |
860 | 0 | *type = attr.flags; |
861 | 0 | if(avp_name) |
862 | 0 | *avp_name = attr.name; |
863 | 0 | if(index) |
864 | 0 | *index = attr.index; |
865 | 0 | } |
866 | 0 | return ret; |
867 | 0 | } |
868 | | |
869 | | |
870 | | /** parse an avp indentifier. |
871 | | * |
872 | | * Parses the following avp indentifier forms: |
873 | | * - "i:<number>" - old form, deprecated (e.g. i:42) |
874 | | * - "s:<string>" - old form, deprecated (e.g. s:foo) |
875 | | * - "<track>.<name>" (e.g.: f.bar) |
876 | | * - "<track>.<name>[<index>]" (e.g.: f.bar[1]) |
877 | | * - "<track><class>.<name>" (e.g: tu.bar) |
878 | | * - "<track><class>.<name>[<index>]" (e.g: fd.bar[2]) |
879 | | * - "<string>" (e.g.: foo) |
880 | | * Where: |
881 | | * \<string\> = ascii string |
882 | | * \<id\> = ascii string w/o '[', ']', '.' and '/' |
883 | | * \<name\> = \<id\> | '/' regex '/' |
884 | | * (Note: regex use is deprecated) |
885 | | * \<track\> = 'f' | 't' |
886 | | * (from or to) |
887 | | * \<class\> = 'r' | 'u' | 'd' | 'g' |
888 | | * (uri, user, domain or global) |
889 | | * \<index\> = \<number\> | '-' \<number\> | '' |
890 | | * (the avp index, if missing it means AVP_INDEX_ALL, but |
891 | | * its use is deprecated) |
892 | | * More examples: |
893 | | * "fr.bar[1]" - from track, uri class, avp "bar", the value 1. |
894 | | * "tu./^foo/" - to track, user class, all avps for which the name |
895 | | * starts with foo (note RE in avp names are deprecated). |
896 | | * "t.did" - to track, "did" avp |
897 | | * |
898 | | * @param name - avp identifier |
899 | | * @param *attr - the result will be stored here |
900 | | * @return 0 on success, -1 on error |
901 | | */ |
902 | | int parse_avp_ident(str *name, avp_ident_t *attr) |
903 | 0 | { |
904 | 0 | unsigned int id; |
905 | 0 | char c; |
906 | 0 | char *p; |
907 | 0 | str s; |
908 | |
|
909 | 0 | if(name == 0 || name->s == 0 || name->len == 0) { |
910 | 0 | LM_ERR("NULL name or name->s or name->len\n"); |
911 | 0 | goto error; |
912 | 0 | } |
913 | | |
914 | 0 | attr->index = 0; |
915 | 0 | LM_DBG("Parsing '%.*s'\n", name->len, name->s); |
916 | 0 | if(name->len >= 2 && name->s[1] == ':') { /* old fashion i: or s: */ |
917 | | /* WARN("i: and s: avp name syntax is deprecated!\n"); */ |
918 | 0 | c = name->s[0]; |
919 | 0 | name->s += 2; |
920 | 0 | name->len -= 2; |
921 | 0 | if(name->len == 0) |
922 | 0 | goto error; |
923 | 0 | switch(c) { |
924 | 0 | case 's': |
925 | 0 | case 'S': |
926 | 0 | attr->flags = AVP_NAME_STR; |
927 | 0 | attr->name.s = *name; |
928 | 0 | break; |
929 | 0 | case 'i': |
930 | 0 | case 'I': |
931 | 0 | attr->flags = 0; |
932 | 0 | if(str2int(name, &id) != 0) { |
933 | 0 | LM_ERR("invalid ID <%.*s> - not a number\n", name->len, |
934 | 0 | name->s); |
935 | 0 | goto error; |
936 | 0 | } |
937 | 0 | attr->name.n = (int)id; |
938 | 0 | break; |
939 | 0 | default: |
940 | 0 | LM_ERR("unsupported type [%c]\n", c); |
941 | 0 | goto error; |
942 | 0 | } |
943 | 0 | } else if((p = memchr(name->s, '.', name->len))) { |
944 | 0 | if(p - name->s == 1) { |
945 | 0 | id = name->s[0]; |
946 | 0 | name->s += 2; |
947 | 0 | name->len -= 2; |
948 | 0 | } else if(p - name->s == 2) { |
949 | 0 | id = name->s[0] << 8 | name->s[1]; |
950 | 0 | name->s += 3; |
951 | 0 | name->len -= 3; |
952 | 0 | } else { |
953 | 0 | LM_ERR("AVP unknown class prefix '%.*s'\n", name->len, name->s); |
954 | 0 | goto error; |
955 | 0 | } |
956 | 0 | if(name->len == 0) { |
957 | 0 | LM_ERR("AVP name not specified after the prefix separator\n"); |
958 | 0 | goto error; |
959 | 0 | } |
960 | 0 | switch(id) { |
961 | 0 | case 'f': |
962 | 0 | attr->flags = AVP_TRACK_FROM; |
963 | 0 | break; |
964 | 0 | case 't': |
965 | 0 | attr->flags = AVP_TRACK_TO; |
966 | 0 | break; |
967 | 0 | case 0x6672: /* 'fr' */ |
968 | 0 | attr->flags = AVP_TRACK_FROM | AVP_CLASS_URI; |
969 | 0 | break; |
970 | 0 | case 0x7472: /* 'tr' */ |
971 | 0 | attr->flags = AVP_TRACK_TO | AVP_CLASS_URI; |
972 | 0 | break; |
973 | 0 | case 0x6675: /* 'fu' */ |
974 | 0 | attr->flags = AVP_TRACK_FROM | AVP_CLASS_USER; |
975 | 0 | break; |
976 | 0 | case 0x7475: /* 'tu' */ |
977 | 0 | attr->flags = AVP_TRACK_TO | AVP_CLASS_USER; |
978 | 0 | break; |
979 | 0 | case 0x6664: /* 'fd' */ |
980 | 0 | attr->flags = AVP_TRACK_FROM | AVP_CLASS_DOMAIN; |
981 | 0 | break; |
982 | 0 | case 0x7464: /* 'td' */ |
983 | 0 | attr->flags = AVP_TRACK_TO | AVP_CLASS_DOMAIN; |
984 | 0 | break; |
985 | 0 | case 'g': |
986 | 0 | attr->flags = AVP_TRACK_ALL | AVP_CLASS_GLOBAL; |
987 | 0 | break; |
988 | 0 | default: |
989 | 0 | if(id < 1 << 8) |
990 | 0 | LM_ERR("AVP unknown class prefix '%c'\n", id); |
991 | 0 | else |
992 | 0 | LM_ERR("AVP unknown class prefix '%c%c'\n", id >> 8, id); |
993 | 0 | goto error; |
994 | 0 | } |
995 | 0 | if(name->s[name->len - 1] == ']') { |
996 | 0 | p = memchr(name->s, '[', name->len); |
997 | 0 | if(!p) { |
998 | 0 | LM_ERR("missing '[' for AVP index\n"); |
999 | 0 | goto error; |
1000 | 0 | } |
1001 | 0 | s.s = p + 1; |
1002 | 0 | s.len = name->len - (p - name->s) - 2; /* [ and ] */ |
1003 | 0 | if(s.len == 0) { |
1004 | 0 | attr->flags |= AVP_INDEX_ALL; |
1005 | 0 | } else { |
1006 | 0 | if(s.s[0] == '-') { |
1007 | 0 | attr->flags |= AVP_INDEX_BACKWARD; |
1008 | 0 | s.s++; |
1009 | 0 | s.len--; |
1010 | 0 | } else { |
1011 | 0 | attr->flags |= AVP_INDEX_FORWARD; |
1012 | 0 | } |
1013 | 0 | if((str2int(&s, &id) != 0) || (id == 0)) { |
1014 | 0 | LM_ERR("Invalid AVP index '%.*s'\n", s.len, s.s); |
1015 | 0 | goto error; |
1016 | 0 | } |
1017 | 0 | attr->index = id; |
1018 | 0 | } |
1019 | 0 | name->len = p - name->s; |
1020 | 0 | } |
1021 | 0 | ERR_IF_CONTAINS(name, '.'); |
1022 | 0 | ERR_IF_CONTAINS(name, '['); |
1023 | 0 | ERR_IF_CONTAINS(name, ']'); |
1024 | 0 | if((name->len > 2) && (name->s[0] == '/') |
1025 | 0 | && (name->s[name->len - 1] == '/')) { |
1026 | 0 | attr->name.re = pkg_malloc(sizeof(regex_t)); |
1027 | 0 | if(!attr->name.re) { |
1028 | 0 | PKG_MEM_ERROR; |
1029 | 0 | goto error; |
1030 | 0 | } |
1031 | 0 | name->s[name->len - 1] = 0; |
1032 | 0 | if(regcomp(attr->name.re, name->s + 1, |
1033 | 0 | REG_EXTENDED | REG_NOSUB | REG_ICASE)) { |
1034 | 0 | pkg_free(attr->name.re); |
1035 | 0 | attr->name.re = 0; |
1036 | 0 | name->s[name->len - 1] = '/'; |
1037 | 0 | goto error; |
1038 | 0 | } |
1039 | 0 | name->s[name->len - 1] = '/'; |
1040 | 0 | attr->flags |= AVP_NAME_RE; |
1041 | 0 | } else { |
1042 | 0 | ERR_IF_CONTAINS(name, '/'); |
1043 | 0 | attr->flags |= AVP_NAME_STR; |
1044 | 0 | attr->name.s = *name; |
1045 | 0 | } |
1046 | 0 | } else { |
1047 | | /*default is string name*/ |
1048 | 0 | attr->flags = AVP_NAME_STR; |
1049 | 0 | attr->name.s = *name; |
1050 | 0 | } |
1051 | | |
1052 | 0 | return 0; |
1053 | 0 | error: |
1054 | 0 | return -1; |
1055 | 0 | } |
1056 | | |
1057 | | void free_avp_ident(avp_ident_t *attr) |
1058 | 0 | { |
1059 | 0 | if(attr->flags & AVP_NAME_RE) { |
1060 | 0 | if(!attr->name.re) { |
1061 | 0 | BUG("attr ident @%p has the regexp flag set, but no regexp.\n", |
1062 | 0 | attr); |
1063 | | #ifdef EXTRA_DEBUG |
1064 | | abort(); |
1065 | | #endif |
1066 | 0 | } else { |
1067 | 0 | regfree(attr->name.re); |
1068 | 0 | pkg_free(attr->name.re); |
1069 | 0 | } |
1070 | 0 | } |
1071 | 0 | } |
1072 | | |
1073 | | int km_parse_avp_spec(str *name, int *type, numstr_ut *avp_name) |
1074 | 0 | { |
1075 | 0 | char *p; |
1076 | 0 | int index = 0; |
1077 | |
|
1078 | 0 | if(name == 0 || name->s == 0 || name->len == 0) |
1079 | 0 | return -1; |
1080 | | |
1081 | 0 | p = (char *)memchr((void *)name->s, ':', name->len); |
1082 | 0 | if(p == NULL) { |
1083 | | /* might be kamailio avp alias or ser avp name style */ |
1084 | 0 | if(lookup_avp_galias(name, type, avp_name) == 0) |
1085 | 0 | return 0; /* found */ |
1086 | 0 | } |
1087 | 0 | return parse_avp_name(name, type, avp_name, &index); |
1088 | 0 | } |
1089 | | |
1090 | | |
1091 | | int parse_avp_spec(str *name, int *type, numstr_ut *avp_name, int *index) |
1092 | 0 | { |
1093 | 0 | str alias; |
1094 | |
|
1095 | 0 | if(name == 0 || name->s == 0 || name->len == 0) |
1096 | 0 | return -1; |
1097 | | |
1098 | 0 | if(name->s[0] == GALIAS_CHAR_MARKER) { |
1099 | | /* it's an avp alias */ |
1100 | 0 | if(name->len == 1) { |
1101 | 0 | LM_ERR("empty alias\n"); |
1102 | 0 | return -1; |
1103 | 0 | } |
1104 | 0 | alias.s = name->s + 1; |
1105 | 0 | alias.len = name->len - 1; |
1106 | 0 | return lookup_avp_galias(&alias, type, avp_name); |
1107 | 0 | } else { |
1108 | 0 | return parse_avp_name(name, type, avp_name, index); |
1109 | 0 | } |
1110 | 0 | } |
1111 | | |
1112 | | void free_avp_name(avp_flags_t *type, numstr_ut *avp_name) |
1113 | 0 | { |
1114 | 0 | if((*type & AVP_NAME_RE) && (avp_name->re)) { |
1115 | 0 | regfree(avp_name->re); |
1116 | 0 | pkg_free(avp_name->re); |
1117 | 0 | avp_name->re = 0; |
1118 | 0 | } |
1119 | 0 | } |
1120 | | |
1121 | | int add_avp_galias_str(char *alias_definition) |
1122 | 0 | { |
1123 | 0 | numstr_ut avp_name; |
1124 | 0 | char *s; |
1125 | 0 | str name; |
1126 | 0 | str alias; |
1127 | 0 | int type; |
1128 | 0 | int index; |
1129 | |
|
1130 | 0 | s = alias_definition; |
1131 | 0 | while(*s && isspace((int)*s)) |
1132 | 0 | s++; |
1133 | |
|
1134 | 0 | while(*s) { |
1135 | | /* parse alias name */ |
1136 | 0 | alias.s = s; |
1137 | 0 | while(*s && *s != ';' && !isspace((int)*s) && *s != '=') |
1138 | 0 | s++; |
1139 | 0 | if(alias.s == s || *s == 0 || *s == ';') |
1140 | 0 | goto parse_error; |
1141 | 0 | alias.len = s - alias.s; |
1142 | 0 | while(*s && isspace((int)*s)) |
1143 | 0 | s++; |
1144 | | /* equal sign */ |
1145 | 0 | if(*s != '=') |
1146 | 0 | goto parse_error; |
1147 | 0 | s++; |
1148 | 0 | while(*s && isspace((int)*s)) |
1149 | 0 | s++; |
1150 | | /* avp name */ |
1151 | 0 | name.s = s; |
1152 | 0 | while(*s && *s != ';' && !isspace((int)*s)) |
1153 | 0 | s++; |
1154 | 0 | if(name.s == s) |
1155 | 0 | goto parse_error; |
1156 | 0 | name.len = s - name.s; |
1157 | 0 | while(*s && isspace((int)*s)) |
1158 | 0 | s++; |
1159 | | /* check end */ |
1160 | 0 | if(*s != 0 && *s != ';') |
1161 | 0 | goto parse_error; |
1162 | 0 | if(*s == ';') { |
1163 | 0 | for(s++; *s && isspace((int)*s); s++) |
1164 | 0 | ; |
1165 | 0 | if(*s == 0) |
1166 | 0 | goto parse_error; |
1167 | 0 | } |
1168 | | |
1169 | 0 | if(parse_avp_name(&name, &type, &avp_name, &index) != 0) { |
1170 | 0 | LM_ERR("<%.*s> not a valid AVP name\n", name.len, name.s); |
1171 | 0 | goto error; |
1172 | 0 | } |
1173 | | |
1174 | 0 | if(add_avp_galias(&alias, type, avp_name) != 0) { |
1175 | 0 | LM_ERR("add global alias failed\n"); |
1176 | 0 | goto error; |
1177 | 0 | } |
1178 | 0 | } /*end while*/ |
1179 | | |
1180 | 0 | return 0; |
1181 | 0 | parse_error: |
1182 | 0 | LM_ERR("parse error in <%s> around pos %ld\n", alias_definition, |
1183 | 0 | (long)(s - alias_definition)); |
1184 | 0 | error: |
1185 | 0 | return -1; |
1186 | 0 | } |
1187 | | |
1188 | | |
1189 | | int destroy_avps(avp_flags_t flags, avp_name_t name, int all) |
1190 | 0 | { |
1191 | 0 | struct search_state st; |
1192 | 0 | avp_t *avp; |
1193 | 0 | int n; |
1194 | |
|
1195 | 0 | n = 0; |
1196 | 0 | avp = search_first_avp(flags, name, 0, &st); |
1197 | 0 | while(avp) { |
1198 | 0 | destroy_avp(avp); |
1199 | 0 | n++; |
1200 | 0 | if(!all) |
1201 | 0 | break; |
1202 | 0 | avp = search_next_avp(&st, 0); |
1203 | 0 | } |
1204 | 0 | return n; |
1205 | 0 | } |
1206 | | |
1207 | | |
1208 | | void delete_avp(avp_flags_t flags, avp_name_t name) |
1209 | 0 | { |
1210 | 0 | struct search_state st; |
1211 | 0 | avp_t *avp; |
1212 | |
|
1213 | 0 | avp = search_first_avp(flags, name, 0, &st); |
1214 | 0 | while(avp) { |
1215 | 0 | destroy_avp(avp); |
1216 | 0 | avp = search_next_avp(&st, 0); |
1217 | 0 | } |
1218 | 0 | } |
1219 | | |
1220 | | /* AVP flags functions */ |
1221 | | |
1222 | | /* name2id conversion is intended to use during fixup (cfg parsing and modinit) only therefore no hash is used */ |
1223 | | avp_flags_t register_avpflag(char *name) |
1224 | 0 | { |
1225 | 0 | avp_flags_t ret; |
1226 | 0 | ret = get_avpflag_no(name); |
1227 | 0 | if(ret == 0) { |
1228 | 0 | if(registered_avpflags_no >= MAX_AVPFLAG) { |
1229 | 0 | LM_ERR("cannot register new avp flag ('%s'), max.number of flags " |
1230 | 0 | "(%d) reached\n", |
1231 | 0 | name, MAX_AVPFLAG); |
1232 | 0 | return -1; |
1233 | 0 | } |
1234 | 0 | ret = 1 << (AVP_CUSTOM_FLAGS + registered_avpflags_no); |
1235 | 0 | registered_avpflags[registered_avpflags_no++] = name; |
1236 | 0 | } |
1237 | 0 | return ret; |
1238 | 0 | } |
1239 | | |
1240 | | avp_flags_t get_avpflag_no(char *name) |
1241 | 0 | { |
1242 | 0 | int i; |
1243 | 0 | for(i = 0; i < registered_avpflags_no; i++) { |
1244 | 0 | if(strcasecmp(name, registered_avpflags[i]) == 0) |
1245 | 0 | return 1 << (AVP_CUSTOM_FLAGS + i); |
1246 | 0 | } |
1247 | 0 | return 0; |
1248 | 0 | } |