parse_rr.c

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