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