/src/opensips/parser/parse_rr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Route & Record-Route header field parser |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /** |
24 | | * History: |
25 | | * -------- |
26 | | * 2003-10-07 parse_rr() split and added parse_rr_body() |
27 | | * 2003-10-21 duplicate_rr() duplicate the whole linked list of RR |
28 | | */ |
29 | | #include <string.h> |
30 | | #include "parse_rr.h" |
31 | | #include "../mem/mem.h" |
32 | | #include "../mem/shm_mem.h" |
33 | | #include "../dprint.h" |
34 | | #include "../trim.h" |
35 | | #include "../ut.h" |
36 | | #include "../errinfo.h" |
37 | | |
38 | | /* |
39 | | * Parse Route or Record-Route body |
40 | | */ |
41 | | static inline int do_parse_rr_body(char *buf, int len, rr_t **head) |
42 | 0 | { |
43 | 0 | rr_t* r, *last; |
44 | 0 | str s; |
45 | 0 | param_hooks_t hooks; |
46 | | |
47 | | /* Make a temporary copy of the string pointer */ |
48 | 0 | if(buf==0 || len<=0) |
49 | 0 | { |
50 | 0 | LM_DBG("no body for record-route\n"); |
51 | 0 | r = NULL; |
52 | 0 | *head = 0; |
53 | 0 | goto parse_error; |
54 | 0 | } |
55 | 0 | s.s = buf; |
56 | 0 | s.len = len; |
57 | 0 | trim_leading(&s); |
58 | |
|
59 | 0 | last = 0; |
60 | |
|
61 | 0 | while(1) { |
62 | | /* Allocate and clear rr structure */ |
63 | 0 | r = (rr_t*)pkg_malloc(sizeof(rr_t)); |
64 | 0 | if (!r) { |
65 | 0 | LM_ERR("no pkg memory left\n"); |
66 | 0 | goto error; |
67 | 0 | } |
68 | 0 | memset(r, 0, sizeof(rr_t)); |
69 | | |
70 | | /* Parse name-addr part of the header */ |
71 | 0 | if (parse_nameaddr(&s, &r->nameaddr) < 0) { |
72 | 0 | LM_ERR("failed to parse name-addr\n"); |
73 | 0 | goto parse_error; |
74 | 0 | } |
75 | 0 | r->len = r->nameaddr.len; |
76 | | |
77 | | /* Shift just behind the closing > */ |
78 | 0 | s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ |
79 | 0 | s.len -= r->nameaddr.len; |
80 | |
|
81 | 0 | trim_leading(&s); /* Skip any white-chars */ |
82 | |
|
83 | 0 | if (s.len == 0) goto ok; /* Nothing left, finish */ |
84 | | |
85 | 0 | if (s.s[0] == ';') { /* Route parameter found */ |
86 | 0 | s.s++; |
87 | 0 | s.len--; |
88 | 0 | trim_leading(&s); |
89 | |
|
90 | 0 | if (s.len == 0) { |
91 | 0 | LM_ERR("failed to parse params\n"); |
92 | 0 | goto parse_error; |
93 | 0 | } |
94 | | |
95 | | /* Parse all parameters */ |
96 | 0 | if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { |
97 | 0 | LM_ERR("failed to parse params\n"); |
98 | 0 | goto parse_error; |
99 | 0 | } |
100 | 0 | r->len = hooks.last_param->name.s + hooks.last_param->len |
101 | 0 | - r->nameaddr.name.s; |
102 | | |
103 | | /* Copy hooks */ |
104 | | /*r->r2 = hooks.rr.r2; */ |
105 | |
|
106 | 0 | trim_leading(&s); |
107 | 0 | if (s.len == 0) goto ok; |
108 | 0 | } |
109 | | |
110 | 0 | if (s.s[0] != ',') { |
111 | 0 | LM_ERR("invalid character '%c', comma expected\n", s.s[0]); |
112 | 0 | goto parse_error; |
113 | 0 | } |
114 | | |
115 | | /* Next character is comma or end of header*/ |
116 | 0 | s.s++; |
117 | 0 | s.len--; |
118 | 0 | trim_leading(&s); |
119 | |
|
120 | 0 | if (s.len == 0) { |
121 | 0 | LM_ERR("text after comma missing\n"); |
122 | 0 | goto parse_error; |
123 | 0 | } |
124 | | |
125 | | /* Append the structure as last parameter of the linked list */ |
126 | 0 | if (!*head) *head = r; |
127 | 0 | if (last) last->next = r; |
128 | 0 | last = r; |
129 | 0 | } |
130 | | |
131 | 0 | parse_error: |
132 | 0 | LM_ERR("failed to parse RR headers\n"); |
133 | 0 | error: |
134 | 0 | if (r) pkg_free(r); |
135 | 0 | free_rr(head); /* Free any contacts created so far */ |
136 | 0 | return -1; |
137 | | |
138 | 0 | ok: |
139 | 0 | if (!*head) *head = r; |
140 | 0 | if (last) last->next = r; |
141 | 0 | return 0; |
142 | 0 | } |
143 | | |
144 | | /* |
145 | | * Wrapper to do_parse_rr_body() for external calls |
146 | | */ |
147 | | int parse_rr_body(char *buf, int len, rr_t **head) |
148 | 0 | { |
149 | 0 | return do_parse_rr_body(buf, len, head); |
150 | 0 | } |
151 | | |
152 | | /* |
153 | | * Parse Route and Record-Route header fields |
154 | | */ |
155 | | int parse_rr(struct hdr_field* _h) |
156 | 0 | { |
157 | 0 | rr_t* r = NULL; |
158 | |
|
159 | 0 | if (!_h) { |
160 | 0 | LM_ERR("invalid parameter value\n"); |
161 | 0 | return -1; |
162 | 0 | } |
163 | | |
164 | 0 | if (_h->parsed) { |
165 | | /* Already parsed, return */ |
166 | 0 | return 0; |
167 | 0 | } |
168 | | |
169 | 0 | if(do_parse_rr_body(_h->body.s, _h->body.len, &r) < 0) { |
170 | 0 | set_err_info(OSER_EC_PARSER, OSER_EL_MEDIUM, |
171 | 0 | "error parsing RR headers"); |
172 | 0 | set_err_reply(400, "bad headers"); |
173 | 0 | return -1; |
174 | 0 | } |
175 | 0 | _h->parsed = (void*)r; |
176 | 0 | return 0; |
177 | 0 | } |
178 | | |
179 | | /* |
180 | | * Free list of rrs |
181 | | * _r is head of the list |
182 | | */ |
183 | | static inline void do_free_rr(rr_t** _r, int _shm) |
184 | 0 | { |
185 | 0 | rr_t* ptr; |
186 | |
|
187 | 0 | while(*_r) { |
188 | 0 | ptr = *_r; |
189 | 0 | *_r = (*_r)->next; |
190 | 0 | if (ptr->params) { |
191 | 0 | if (_shm) shm_free_params(ptr->params); |
192 | 0 | else free_params(ptr->params); |
193 | 0 | } |
194 | 0 | if (_shm) shm_free(ptr); |
195 | 0 | else pkg_free(ptr); |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | | |
200 | | /* |
201 | | * Free list of rrs |
202 | | * _r is head of the list |
203 | | */ |
204 | | |
205 | | void free_rr(rr_t** _r) |
206 | 0 | { |
207 | 0 | do_free_rr(_r, 0); |
208 | 0 | } |
209 | | |
210 | | |
211 | | /* |
212 | | * Free list of rrs |
213 | | * _r is head of the list |
214 | | */ |
215 | | |
216 | | void shm_free_rr(rr_t** _r) |
217 | 0 | { |
218 | 0 | do_free_rr(_r, 1); |
219 | 0 | } |
220 | | |
221 | | |
222 | | /* |
223 | | * Print list of RRs, just for debugging |
224 | | */ |
225 | | void print_rr(FILE* _o, rr_t* _r) |
226 | 0 | { |
227 | 0 | rr_t* ptr; |
228 | |
|
229 | 0 | ptr = _r; |
230 | |
|
231 | 0 | while(ptr) { |
232 | 0 | fprintf(_o, "---RR---\n"); |
233 | 0 | print_nameaddr(_o, &ptr->nameaddr); |
234 | 0 | fprintf(_o, "r2 : %p\n", ptr->r2); |
235 | 0 | if (ptr->params) { |
236 | 0 | print_params(ptr->params); |
237 | 0 | } |
238 | 0 | fprintf(_o, "len: %d\n", ptr->len); |
239 | 0 | fprintf(_o, "---/RR---\n"); |
240 | 0 | ptr = ptr->next; |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | |
245 | | /* |
246 | | * Translate all pointers in the structure and also |
247 | | * in all parameters in the list |
248 | | */ |
249 | | static inline void xlate_pointers(rr_t* _orig, rr_t* _r) |
250 | 0 | { |
251 | 0 | param_t* ptr; |
252 | 0 | _r->nameaddr.uri.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, _r->nameaddr.uri.s); |
253 | |
|
254 | 0 | ptr = _r->params; |
255 | 0 | while(ptr) { |
256 | | /* if (ptr->type == P_R2) _r->r2 = ptr; */ |
257 | 0 | ptr->name.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->name.s); |
258 | 0 | ptr->body.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->body.s); |
259 | 0 | ptr = ptr->next; |
260 | 0 | } |
261 | 0 | } |
262 | | |
263 | | |
264 | | /* |
265 | | * Duplicate a single rr_t structure using pkg_malloc or shm_malloc |
266 | | */ |
267 | | static inline int do_duplicate_rr(rr_t** _new, rr_t* _r, int _shm, int _first) |
268 | 0 | { |
269 | 0 | int len, ret; |
270 | 0 | rr_t* res, *prev, *it; |
271 | |
|
272 | 0 | if (!_new || !_r) { |
273 | 0 | LM_ERR("invalid parameter value\n"); |
274 | 0 | return -1; |
275 | 0 | } |
276 | 0 | prev = NULL; |
277 | 0 | *_new = NULL; |
278 | 0 | it = _r; |
279 | 0 | while(it) |
280 | 0 | { |
281 | 0 | if (it->params) { |
282 | 0 | len = it->params->name.s + it->params->len - it->nameaddr.name.s; |
283 | 0 | } else { |
284 | 0 | len = it->nameaddr.len; |
285 | 0 | } |
286 | |
|
287 | 0 | if (_shm) res = shm_malloc(sizeof(rr_t) + len); |
288 | 0 | else res = pkg_malloc(sizeof(rr_t) + len); |
289 | 0 | if (!res) { |
290 | 0 | LM_ERR("no shm memory left\n"); |
291 | 0 | goto error; |
292 | 0 | } |
293 | 0 | memcpy(res, it, sizeof(rr_t)); |
294 | |
|
295 | 0 | res->nameaddr.name.s = (char*)res + sizeof(rr_t); |
296 | 0 | memcpy(res->nameaddr.name.s, it->nameaddr.name.s, len); |
297 | |
|
298 | 0 | if (_shm) { |
299 | 0 | ret = shm_duplicate_params(&res->params, it->params); |
300 | 0 | } else { |
301 | 0 | ret = duplicate_params(&res->params, it->params); |
302 | 0 | } |
303 | |
|
304 | 0 | if (ret < 0) { |
305 | 0 | LM_ERR("failed to duplicate parameters\n"); |
306 | 0 | if (_shm) shm_free(res); |
307 | 0 | else pkg_free(res); |
308 | 0 | goto error; |
309 | 0 | } |
310 | | |
311 | 0 | xlate_pointers(it, res); |
312 | |
|
313 | 0 | res->next=NULL; |
314 | 0 | if(*_new==NULL) |
315 | 0 | *_new = res; |
316 | |
|
317 | 0 | if (_first) |
318 | 0 | return 0; |
319 | | |
320 | 0 | if(prev) |
321 | 0 | prev->next = res; |
322 | 0 | prev = res; |
323 | 0 | it = it->next; |
324 | 0 | } |
325 | 0 | return 0; |
326 | 0 | error: |
327 | 0 | if (_shm) shm_free_rr(_new); |
328 | 0 | else free_rr(_new); |
329 | 0 | *_new = NULL; |
330 | 0 | return -1; |
331 | 0 | } |
332 | | |
333 | | |
334 | | /* |
335 | | * Duplicate a single rr_t structure or the whole list (based on |
336 | | * "first" param) using pkg_malloc |
337 | | */ |
338 | | int duplicate_rr(rr_t** _new, rr_t* _r, int first) |
339 | 0 | { |
340 | 0 | return do_duplicate_rr(_new, _r, 0, first); |
341 | 0 | } |
342 | | |
343 | | |
344 | | /* |
345 | | * Duplicate a single rr_t structure or the whole list (based on |
346 | | * "first" param) using shm_malloc |
347 | | */ |
348 | | int shm_duplicate_rr(rr_t** _new, rr_t* _r, int first) |
349 | 0 | { |
350 | 0 | return do_duplicate_rr(_new, _r, 1, first); |
351 | 0 | } |
352 | | |
353 | | |
354 | | /** |
355 | | * get first RR header and print comma separated bodies in oroute |
356 | | * - order = 0 normal; order = 1 reverse |
357 | | * - no_change = 1 do not perform any change/linking over the input hdr list |
358 | | * (all parsing is localy done with no effect over the hdrs) |
359 | | * - nb_recs - input=skip number of rr; output=number of printed rrs |
360 | | */ |
361 | | int print_rr_body(struct hdr_field *iroute, str *oroute, int order, |
362 | | int no_change, unsigned int * nb_recs) |
363 | 0 | { |
364 | 0 | rr_t *p; |
365 | 0 | int n = 0, nr=0; |
366 | 0 | int i = 0; |
367 | 0 | int route_len; |
368 | 0 | #define MAX_RR_HDRS 64 |
369 | 0 | static str route[MAX_RR_HDRS]; |
370 | 0 | char *cp, *start; |
371 | 0 | struct hdr_field tmp, *hdr; |
372 | |
|
373 | 0 | if(iroute==NULL) |
374 | 0 | return 0; |
375 | | |
376 | 0 | route_len= 0; |
377 | 0 | memset(route, 0, MAX_RR_HDRS*sizeof(str)); |
378 | |
|
379 | 0 | while (iroute!=NULL) |
380 | 0 | { |
381 | 0 | if (no_change) { |
382 | 0 | memcpy( &tmp, iroute, sizeof(tmp)); |
383 | 0 | tmp.parsed = NULL; |
384 | 0 | hdr=&tmp; |
385 | 0 | }else{ |
386 | 0 | hdr=iroute; |
387 | 0 | } |
388 | 0 | if (parse_rr(hdr) < 0) |
389 | 0 | { |
390 | 0 | LM_ERR("failed to parse RR\n"); |
391 | 0 | goto error; |
392 | 0 | } |
393 | | |
394 | 0 | p =(rr_t*)hdr->parsed; |
395 | 0 | while (p) |
396 | 0 | { |
397 | 0 | route[n].s = p->nameaddr.name.s; |
398 | 0 | route[n].len = p->len; |
399 | 0 | LM_DBG("current rr is %.*s\n", route[n].len, route[n].s); |
400 | |
|
401 | 0 | n++; |
402 | 0 | if(n==MAX_RR_HDRS) |
403 | 0 | { |
404 | 0 | LM_ERR("too many RR\n"); |
405 | 0 | goto error; |
406 | 0 | } |
407 | 0 | p = p->next; |
408 | 0 | } |
409 | 0 | if (no_change) |
410 | 0 | free_rr( (rr_t**)&tmp.parsed ); |
411 | 0 | iroute = iroute->sibling; |
412 | 0 | } |
413 | | |
414 | 0 | for(i=0;i<n;i++){ |
415 | 0 | if(!nb_recs || (nb_recs && |
416 | 0 | ( (!order&& (i>=*nb_recs)) || (order && (i<=(n-*nb_recs)) )) ) ) |
417 | 0 | { |
418 | 0 | route_len+= route[i].len; |
419 | 0 | nr++; |
420 | 0 | } |
421 | |
|
422 | 0 | } |
423 | |
|
424 | 0 | if(nb_recs) |
425 | 0 | LM_DBG("skipping %i route records\n", *nb_recs); |
426 | |
|
427 | 0 | route_len += --nr; /* for commas */ |
428 | |
|
429 | 0 | oroute->s=(char*)pkg_malloc(route_len); |
430 | | |
431 | |
|
432 | 0 | if(oroute->s==0) |
433 | 0 | { |
434 | 0 | LM_ERR("no more pkg mem\n"); |
435 | 0 | goto error; |
436 | 0 | } |
437 | 0 | cp = start = oroute->s; |
438 | 0 | if(order==0) |
439 | 0 | { |
440 | 0 | i= (nb_recs == NULL) ? 0:*nb_recs; |
441 | |
|
442 | 0 | while (i<n) |
443 | 0 | { |
444 | 0 | memcpy(cp, route[i].s, route[i].len); |
445 | 0 | cp += route[i].len; |
446 | 0 | if (++i<n) |
447 | 0 | *(cp++) = ','; |
448 | 0 | } |
449 | 0 | } else { |
450 | |
|
451 | 0 | i = (nb_recs == NULL) ? n-1 : (n-*nb_recs-1); |
452 | |
|
453 | 0 | while (i>=0) |
454 | 0 | { |
455 | 0 | memcpy(cp, route[i].s, route[i].len); |
456 | 0 | cp += route[i].len; |
457 | 0 | if (i-->0) |
458 | 0 | *(cp++) = ','; |
459 | 0 | } |
460 | 0 | } |
461 | 0 | oroute->len=cp - start; |
462 | |
|
463 | 0 | LM_DBG("out rr [%.*s]\n", oroute->len, oroute->s); |
464 | 0 | LM_DBG("we have %i records\n", n); |
465 | 0 | if(nb_recs != NULL) |
466 | 0 | *nb_recs = (unsigned int)n; |
467 | |
|
468 | 0 | return 0; |
469 | | |
470 | 0 | error: |
471 | 0 | return -1; |
472 | 0 | } |
473 | | |
474 | | |
475 | | |
476 | | /* |
477 | | * Path must be available. Function returns the first uri |
478 | | * from Path without any duplication. |
479 | | */ |
480 | | int get_path_dst_uri(str *_p, str *_dst) |
481 | 0 | { |
482 | 0 | rr_t *route = 0; |
483 | |
|
484 | 0 | LM_DBG("path for branch: '%.*s'\n", _p->len, _p->s); |
485 | |
|
486 | 0 | if(parse_rr_body(_p->s, _p->len, &route) < 0) { |
487 | 0 | LM_ERR("failed to parse Path body\n"); |
488 | 0 | return -1; |
489 | 0 | } |
490 | 0 | if(!route) { |
491 | 0 | LM_ERR("failed to parse Path body no head found\n"); |
492 | 0 | return -1; |
493 | 0 | } |
494 | | |
495 | 0 | *_dst = route->nameaddr.uri; |
496 | 0 | free_rr(&route); |
497 | |
|
498 | 0 | return 0; |
499 | 0 | } |