parse_rr.c

Go to the documentation of this file.
00001 /*
00002  * $Id: parse_rr.c 4720 2008-08-23 10:56:15Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 /*!
00024  * \file
00025  * \brief Route & Record-Route header field parser
00026  * \ingroup parser
00027  */
00028 
00029 #include <string.h>
00030 #include "parse_rr.h"
00031 #include "../mem/mem.h"
00032 #include "../mem/shm_mem.h"
00033 #include "../dprint.h"
00034 #include "../trim.h"
00035 #include "../ut.h"
00036 
00037 /*!
00038  * Parse Route or Record-Route body
00039  */
00040 static inline int do_parse_rr_body(char *buf, int len, rr_t **head)
00041 {
00042    rr_t* r, *last;
00043    str s;
00044    param_hooks_t hooks;
00045 
00046    /* Make a temporary copy of the string pointer */
00047    if(buf==0 || len<=0)
00048    {
00049       LM_DBG("no body for record-route\n");
00050       *head = 0;
00051       return -2;
00052    }
00053    s.s = buf;
00054    s.len = len;
00055    trim_leading(&s);
00056 
00057    last = 0;
00058 
00059    while(1) {
00060            /* Allocate and clear rr structure */
00061       r = (rr_t*)pkg_malloc(sizeof(rr_t));
00062       if (!r) {
00063          LM_ERR("no pkg memory left\n");
00064          goto error;
00065       }
00066       memset(r, 0, sizeof(rr_t));
00067       
00068            /* Parse name-addr part of the header */
00069       if (parse_nameaddr(&s, &r->nameaddr) < 0) {
00070          LM_ERR("failed to parse name-addr\n");
00071          goto error;
00072       }
00073       r->len = r->nameaddr.len;
00074 
00075            /* Shift just behind the closing > */
00076       s.s = r->nameaddr.name.s + r->nameaddr.len;  /* Point just behind > */
00077       s.len -= r->nameaddr.len;
00078 
00079       trim_leading(&s); /* Skip any white-chars */
00080 
00081       if (s.len == 0) goto ok; /* Nothing left, finish */
00082       
00083       if (s.s[0] == ';') {         /* Route parameter found */
00084          s.s++;
00085          s.len--;
00086          trim_leading(&s);
00087          
00088          if (s.len == 0) {
00089             LM_ERR("failed to parse params\n");
00090             goto error;
00091          }
00092 
00093               /* Parse all parameters */
00094          if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) {
00095             LM_ERR("failed to parse params\n");
00096             goto error;
00097          }
00098          r->len = r->params->name.s + r->params->len - r->nameaddr.name.s;
00099 
00100               /* Copy hooks */
00101               /*r->r2 = hooks.rr.r2; */
00102 
00103          trim_leading(&s);
00104          if (s.len == 0) goto ok;
00105       }
00106 
00107       if (s.s[0] != ',') {
00108          LM_ERR("invalid character '%c', comma expected\n", s.s[0]);
00109          goto error;
00110       }
00111       
00112            /* Next character is comma or end of header*/
00113       s.s++;
00114       s.len--;
00115       trim_leading(&s);
00116 
00117       if (s.len == 0) {
00118          LM_ERR("text after comma missing\n");
00119          goto error;
00120       }
00121 
00122            /* Append the structure as last parameter of the linked list */
00123       if (!*head) *head = r;
00124       if (last) last->next = r;
00125       last = r;
00126    }
00127 
00128  error:
00129    if (r) pkg_free(r);
00130    free_rr(head); /* Free any contacts created so far */
00131    return -1;
00132 
00133  ok:
00134    if (!*head) *head = r;
00135    if (last) last->next = r;
00136    return 0;
00137 }
00138 
00139 /*!
00140  * Wrapper to do_parse_rr_body() for external calls
00141  */
00142 int parse_rr_body(char *buf, int len, rr_t **head)
00143 {
00144    return do_parse_rr_body(buf, len, head);
00145 }
00146 
00147 /*!
00148  * Parse Route and Record-Route header fields
00149  */
00150 int parse_rr(struct hdr_field* _h)
00151 {
00152    rr_t* r = NULL;
00153 
00154    if (!_h) {
00155       LM_ERR("invalid parameter value\n");
00156       return -1;
00157    }
00158 
00159    if (_h->parsed) {
00160            /* Already parsed, return */
00161       return 0;
00162    }
00163 
00164    if(do_parse_rr_body(_h->body.s, _h->body.len, &r) < 0)
00165       return -1;
00166    _h->parsed = (void*)r;
00167    return 0;
00168 }
00169 
00170 /*!
00171  * Free list of rrs
00172  * _r is head of the list
00173  */
00174 static inline void do_free_rr(rr_t** _r, int _shm)
00175 {
00176    rr_t* ptr;
00177 
00178    while(*_r) {
00179       ptr = *_r;
00180       *_r = (*_r)->next;
00181       if (ptr->params) {
00182          if (_shm) shm_free_params(ptr->params);
00183          else free_params(ptr->params);
00184       }
00185       if (_shm) shm_free(ptr);
00186       else pkg_free(ptr);
00187    }
00188 }
00189 
00190 
00191 /*!
00192  * Free list of rrs in pkg_mem
00193  * _r is head of the list
00194  */
00195 
00196 void free_rr(rr_t** _r)
00197 {
00198    do_free_rr(_r, 0);
00199 }
00200 
00201 
00202 /*!
00203  * Free list of rrs in shm_mem
00204  * _r is head of the list
00205  */
00206 
00207 void shm_free_rr(rr_t** _r)
00208 {
00209    do_free_rr(_r, 1);
00210 }
00211 
00212 
00213 /*!
00214  * Print list of RRs, just for debugging
00215  */
00216 void print_rr(FILE* _o, rr_t* _r)
00217 {
00218    rr_t* ptr;
00219 
00220    ptr = _r;
00221 
00222    while(ptr) {
00223       fprintf(_o, "---RR---\n");
00224       print_nameaddr(_o, &ptr->nameaddr);
00225       fprintf(_o, "r2 : %p\n", ptr->r2);
00226       if (ptr->params) {
00227          print_params(_o, ptr->params);
00228       }
00229       fprintf(_o, "len: %d\n", ptr->len);
00230       fprintf(_o, "---/RR---\n");
00231       ptr = ptr->next;
00232    }
00233 }
00234 
00235 
00236 /*!
00237  * Translate all pointers in the structure and also
00238  * in all parameters in the list
00239  */
00240 static inline void xlate_pointers(rr_t* _orig, rr_t* _r)
00241 {
00242    param_t* ptr;
00243    _r->nameaddr.uri.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, _r->nameaddr.uri.s);
00244    
00245    ptr = _r->params;
00246    while(ptr) {
00247            /*     if (ptr->type == P_R2) _r->r2 = ptr; */
00248       ptr->name.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->name.s);
00249       ptr->body.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->body.s);      
00250       ptr = ptr->next;
00251    }
00252 }
00253 
00254 
00255 /*!
00256  * Duplicate a single rr_t structure using pkg_malloc or shm_malloc
00257  */
00258 static inline int do_duplicate_rr(rr_t** _new, rr_t* _r, int _shm, int _first)
00259 {
00260    int len, ret;
00261    rr_t* res, *prev, *it;
00262 
00263    if (!_new || !_r) {
00264       LM_ERR("invalid parameter value\n");
00265       return -1;
00266    }
00267    prev  = NULL;
00268    *_new = NULL;
00269    it    = _r;
00270    while(it)
00271    {
00272       if (it->params) {
00273          len = it->params->name.s + it->params->len - it->nameaddr.name.s;
00274       } else {
00275          len = it->nameaddr.len;
00276       }
00277 
00278       if (_shm) res = shm_malloc(sizeof(rr_t) + len);
00279       else res = pkg_malloc(sizeof(rr_t) + len);
00280       if (!res) {
00281          LM_ERR("no shm memory left\n");
00282          goto error;
00283       }
00284       memcpy(res, it, sizeof(rr_t));
00285 
00286       res->nameaddr.name.s = (char*)res + sizeof(rr_t);
00287       memcpy(res->nameaddr.name.s, it->nameaddr.name.s, len);
00288 
00289       if (_shm) {
00290          ret = shm_duplicate_params(&res->params, it->params);
00291       } else {
00292          ret = duplicate_params(&res->params, it->params);
00293       }
00294 
00295       if (ret < 0) {
00296          LM_ERR("failed to duplicate parameters\n");
00297          if (_shm) shm_free(res);
00298          else pkg_free(res);
00299          goto error;
00300       }
00301 
00302       xlate_pointers(it, res);
00303 
00304       res->next=NULL;
00305       if(*_new==NULL)
00306          *_new = res;
00307 
00308       if (_first)
00309          return 0;
00310 
00311       if(prev)
00312          prev->next = res;
00313       prev = res;
00314       it = it->next;
00315    }
00316    return 0;
00317 error:
00318    if (_shm) shm_free_rr(_new);
00319    else free_rr(_new);
00320    *_new = NULL;
00321    return -1;
00322 }
00323 
00324 
00325 /*!
00326  * Duplicate a single rr_t structure or the whole list (based on
00327  * "first" param) using pkg_malloc
00328  */
00329 int duplicate_rr(rr_t** _new, rr_t* _r, int first)
00330 {
00331    return do_duplicate_rr(_new, _r, 0, first);
00332 }
00333 
00334 
00335 /*!
00336  * Duplicate a single rr_t structure or the whole list (based on
00337  * "first" param) using shm_malloc
00338  */
00339 int shm_duplicate_rr(rr_t** _new, rr_t* _r, int first)
00340 {
00341    return do_duplicate_rr(_new, _r, 1, first);
00342 }
00343 
00344 
00345 /*!
00346  * get first RR header and print comma separated bodies in oroute
00347  * - order = 0 normal; order = 1 reverse
00348  * - nb_recs - input=skip number of rr; output=number of printed rrs
00349  */
00350 int print_rr_body(struct hdr_field *iroute, str *oroute, int order,
00351                                     unsigned int * nb_recs)
00352 {
00353    rr_t *p;
00354    int n = 0, nr=0;
00355    int i = 0;
00356    int route_len;
00357 #define MAX_RR_HDRS  64
00358    static str route[MAX_RR_HDRS];
00359    char *cp, *start;
00360 
00361    if(iroute==NULL)
00362       return 0;
00363 
00364    route_len= 0;
00365    memset(route, 0, MAX_RR_HDRS*sizeof(str));
00366 
00367    while (iroute!=NULL) 
00368    {
00369       if (parse_rr(iroute) < 0) 
00370       {
00371          LM_ERR("failed to parse RR\n");
00372          goto error;
00373       }
00374 
00375       p =(rr_t*)iroute->parsed;
00376       while (p)
00377       {
00378          route[n].s = p->nameaddr.name.s;
00379          route[n].len = p->len;
00380          LM_DBG("current rr is %.*s\n", route[n].len, route[n].s);
00381 
00382          n++;
00383          if(n==MAX_RR_HDRS)
00384          {
00385             LM_ERR("too many RR\n");
00386             goto error;
00387          }
00388          p = p->next;
00389       }
00390       iroute = iroute->sibling;
00391    }
00392 
00393    for(i=0;i<n;i++){
00394       if(!nb_recs || (nb_recs && 
00395        ( (!order&& (i>=*nb_recs)) || (order && (i<=(n-*nb_recs)) )) ) )
00396       {
00397          route_len+= route[i].len;
00398          nr++;
00399       }
00400    
00401    }
00402 
00403    if(nb_recs)
00404       LM_DBG("skipping %i route records\n", *nb_recs);
00405    
00406    route_len += --nr; /* for commas */
00407 
00408    oroute->s=(char*)pkg_malloc(route_len);
00409 
00410 
00411    if(oroute->s==0)
00412    {
00413       LM_ERR("no more pkg mem\n");
00414       goto error;
00415    }
00416    cp = start = oroute->s;
00417    if(order==0)
00418    {
00419       i= (nb_recs == NULL) ? 0:*nb_recs;
00420 
00421       while (i<n)
00422       {
00423          memcpy(cp, route[i].s, route[i].len);
00424          cp += route[i].len;
00425          if (++i<n)
00426             *(cp++) = ',';
00427       }
00428    } else {
00429       
00430       i = (nb_recs == NULL) ? n-1 : (n-*nb_recs-1);
00431          
00432       while (i>=0)
00433       {
00434          memcpy(cp, route[i].s, route[i].len);
00435          cp += route[i].len;
00436          if (i-->0)
00437             *(cp++) = ',';
00438       }
00439    }
00440    oroute->len=cp - start;
00441 
00442    LM_DBG("out rr [%.*s]\n", oroute->len, oroute->s);
00443    LM_DBG("we have %i records\n", n);
00444    if(nb_recs != NULL)
00445       *nb_recs = (unsigned int)n; 
00446 
00447    return 0;
00448 
00449 error:
00450    return -1;
00451 }
00452 
00453 
00454 
00455 /*!
00456  * Path must be available. Function returns the first uri 
00457  * from Path without any duplication.
00458  */
00459 int get_path_dst_uri(str *_p, str *_dst)
00460 {
00461    rr_t *route = 0;
00462 
00463    LM_DBG("path for branch: '%.*s'\n", _p->len, _p->s);
00464 
00465    if(parse_rr_body(_p->s, _p->len, &route) < 0) {
00466       LM_ERR("failed to parse Path body\n");
00467       return -1;
00468    }
00469    if(!route) {
00470       LM_ERR("failed to parse Path body no head found\n");
00471       return -1;
00472    }
00473 
00474    *_dst = route->nameaddr.uri;
00475    free_rr(&route);
00476 
00477    return 0;
00478 }

Generated on Thu May 24 00:00:28 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6