/* * $Id$ * * Route & Record-Route header field parser * * Copyright (C) 2001-2003 Fhg Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <string.h> #include "parse_rr.h" #include "../mem/mem.h" #include "../mem/shm_mem.h" #include "../dprint.h" #include "../trim.h" #include "../ut.h" /* * Parse Route and Record-Route header fields */ int parse_rr(struct hdr_field* _h) { rr_t* r, *last; str s; param_hooks_t hooks; if (!_h) { LOG(L_ERR, "parse_rr(): Invalid parameter value\n"); return -1; } if (_h->parsed) { /* Already parsed, return */ return 0; } /* Make a temporary copy of the string pointer */ s.s = _h->body.s; s.len = _h->body.len; trim_leading(&s); last = 0; while(1) { /* Allocate and clear rr stucture */ r = (rr_t*)pkg_malloc(sizeof(rr_t)); if (!r) { LOG(L_ERR, "parse_rr(): No memory left\n"); goto error; } memset(r, 0, sizeof(rr_t)); /* Parse name-addr part of the header */ if (parse_nameaddr(&s, &r->nameaddr) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing name-addr\n"); goto error; } r->len = r->nameaddr.len; /* Shift just behind the closing > */ s.s = r->nameaddr.name.s + r->nameaddr.len; /* Point just behind > */ s.len -= r->nameaddr.len; trim_leading(&s); /* Skip any whitechars */ /* Nothing left, finish */ if (s.len == 0) goto ok; if (s.s[0] == ';') { /* Contact parameter found */ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } /* Parse all parameters */ if (parse_params(&s, CLASS_ANY, &hooks, &r->params) < 0) { LOG(L_ERR, "parse_rr(): Error while parsing params\n"); goto error; } r->len = r->params->name.s + r->params->len - r->nameaddr.name.s; /* Copy hooks */ /*r->r2 = hooks.rr.r2; */ trim_leading(&s); if (s.len == 0) goto ok; } if (s.s[0] != ',') { LOG(L_ERR, "parse_rr(): Invalid character '%c', comma expected\n", s.s[0]); goto error; } /* Next character is comma or end of header*/ s.s++; s.len--; trim_leading(&s); if (s.len == 0) { LOG(L_ERR, "parse_rr(): Text after comma missing\n"); goto error; } /* Append the structure as last parameter of the linked list */ if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; last = r; } error: if (r) pkg_free(r); free_rr((rr_t**)&_h->parsed); /* Free any contacts created so far */ return -1; ok: if (!_h->parsed) _h->parsed = (void*)r; if (last) last->next = r; return 0; } /* * Free list of rrs * _r is head of the list */ static inline void do_free_rr(rr_t** _r, int _shm) { rr_t* ptr; while(*_r) { ptr = *_r; *_r = (*_r)->next; if (ptr->params) { if (_shm) shm_free_params(ptr->params); else free_params(ptr->params); } if (_shm) shm_free(ptr); else pkg_free(ptr); } } /* * Free list of rrs * _r is head of the list */ void free_rr(rr_t** _r) { do_free_rr(_r, 0); } /* * Free list of rrs * _r is head of the list */ void shm_free_rr(rr_t** _r) { do_free_rr(_r, 1); } /* * Print list of RRs, just for debugging */ void print_rr(FILE* _o, rr_t* _r) { rr_t* ptr; ptr = _r; while(ptr) { fprintf(_o, "---RR---\n"); print_nameaddr(_o, &ptr->nameaddr); fprintf(_o, "r2 : %p\n", ptr->r2); if (ptr->params) { print_params(_o, ptr->params); } fprintf(_o, "len: %d\n", ptr->len); fprintf(_o, "---/RR---\n"); ptr = ptr->next; } } /* * Translate all pointers in the structure and also * in all parameters in the list */ static inline void xlate_pointers(rr_t* _orig, rr_t* _r) { param_t* ptr; _r->nameaddr.uri.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, _r->nameaddr.uri.s); ptr = _r->params; while(ptr) { /* if (ptr->type == P_R2) _r->r2 = ptr; */ ptr->name.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->name.s); ptr->body.s = translate_pointer(_r->nameaddr.name.s, _orig->nameaddr.name.s, ptr->body.s); ptr = ptr->next; } } /* * Duplicate a single rr_t structure using pkg_malloc or shm_malloc */ static inline int do_duplicate_rr(rr_t** _new, rr_t* _r, int _shm) { int len, ret; rr_t* res; if (!_new || !_r) { LOG(L_ERR, "duplicate_rr(): Invalid parameter value\n"); return -1; } if (_r->params) { len = _r->params->name.s + _r->params->len - _r->nameaddr.name.s; } else { len = _r->nameaddr.len; } if (_shm) res = shm_malloc(sizeof(rr_t) + len); else res = pkg_malloc(sizeof(rr_t) + len); if (!res) { LOG(L_ERR, "duplicate_rr(): No memory left\n"); return -2; } memcpy(res, _r, sizeof(rr_t)); res->nameaddr.name.s = (char*)res + sizeof(rr_t); memcpy(res->nameaddr.name.s, _r->nameaddr.name.s, len); if (_shm) { ret = shm_duplicate_params(&res->params, _r->params); } else { ret = duplicate_params(&res->params, _r->params); } if (ret < 0) { LOG(L_ERR, "Error while duplicating parameters\n"); if (_shm) shm_free(res); else pkg_free(res); return -3; } xlate_pointers(_r, res); *_new = res; return 0; } /* * Duplicate a single rr_t structure using pkg_malloc */ int duplicate_rr(rr_t** _new, rr_t* _r) { return do_duplicate_rr(_new, _r, 0); } /* * Duplicate a single rr_t structure using pkg_malloc */ int shm_duplicate_rr(rr_t** _new, rr_t* _r) { return do_duplicate_rr(_new, _r, 1); }