parse_param.c

Go to the documentation of this file.
00001 /*
00002  * $Id: parse_param.c 5594 2009-02-12 14:58:37Z miconda $
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 Generic Parameter Parser
00026  * \ingroup parser
00027  */
00028 
00029 #include <string.h>
00030 #include "../str.h"
00031 #include "../ut.h"
00032 #include "../dprint.h"
00033 #include "../trim.h"
00034 #include "../mem/mem.h"
00035 #include "../mem/shm_mem.h"
00036 #include "parse_param.h"
00037 
00038 
00039 /*!
00040  * Try to find out parameter name, recognized parameters
00041  * are q, expires and methods
00042  */
00043 static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
00044 {
00045 
00046    if (!_p->name.s) {
00047       LM_ERR("empty value\n");
00048       return;
00049    }
00050    switch(_p->name.s[0]) {
00051    case 'q':
00052    case 'Q':
00053       if (_p->name.len == 1) {
00054          _p->type = P_Q;
00055          _h->contact.q = _p;
00056       }
00057       break;
00058       
00059    case 'e':
00060    case 'E':
00061       if ((_p->name.len == 7) &&
00062           (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
00063          _p->type = P_EXPIRES;
00064          _h->contact.expires = _p;
00065       }
00066       break;
00067       
00068    case 'm':
00069    case 'M':
00070       if ((_p->name.len == 7) &&
00071           (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
00072          _p->type = P_METHODS;
00073          _h->contact.methods = _p;
00074       }
00075       break;
00076       
00077    case 'r':
00078    case 'R':
00079       if ((_p->name.len == 8) &&
00080           (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
00081          _p->type = P_RECEIVED;
00082          _h->contact.received = _p;
00083       }
00084       break;
00085    }
00086 }
00087 
00088 
00089 /*!
00090  * Try to find out parameter name, recognized parameters
00091  * are transport, lr, r2, maddr
00092  */
00093 static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
00094 {
00095 
00096    if (!_p->name.s) {
00097       LM_ERR("empty value\n");
00098       return;
00099    }
00100    switch(_p->name.s[0]) {
00101    case 't':
00102    case 'T':
00103       if ((_p->name.len == 9) &&
00104           (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
00105          _p->type = P_TRANSPORT;
00106          _h->uri.transport = _p;
00107       } else if (_p->name.len == 2) {
00108          if (((_p->name.s[1] == 't') || (_p->name.s[1] == 'T')) &&
00109              ((_p->name.s[2] == 'l') || (_p->name.s[2] == 'L'))) {
00110             _p->type = P_TTL;
00111             _h->uri.ttl = _p;
00112          }
00113       }
00114       break;
00115 
00116    case 'l':
00117    case 'L':
00118       if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
00119          _p->type = P_LR;
00120          _h->uri.lr = _p;
00121       }
00122       break;
00123 
00124    case 'r':
00125    case 'R':
00126       if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
00127          _p->type = P_R2;
00128          _h->uri.r2 = _p;
00129       }
00130       break;
00131 
00132    case 'm':
00133    case 'M':
00134       if ((_p->name.len == 5) &&
00135           (!strncasecmp(_p->name.s + 1, "addr", 4))) {
00136          _p->type = P_MADDR;
00137          _h->uri.maddr = _p;
00138       }
00139       break;
00140       
00141    case 'd':
00142    case 'D':
00143       if ((_p->name.len == 5) &&
00144           (!strncasecmp(_p->name.s + 1, "stip", 4))) {
00145          _p->type = P_DSTIP;
00146          _h->uri.dstip = _p;
00147       } else if ((_p->name.len == 7) &&
00148             (!strncasecmp(_p->name.s + 1, "stport", 6))) {
00149          _p->type = P_DSTPORT;
00150          _h->uri.dstport = _p;
00151       }
00152       break;
00153    }
00154 
00155 }
00156 
00157 
00158 /*!
00159  * Parse quoted string in a parameter body
00160  * return the string without quotes in _r
00161  * parameter and update _s to point behind the
00162  * closing quote
00163  * \return zero on success, negative result on error
00164  */
00165 static inline int parse_quoted_param(str* _s, str* _r)
00166 {
00167    char* end_quote;
00168 
00169         /* The string must have at least
00170          * surrounding quotes
00171          */
00172    if (_s->len < 2) {
00173       return -1;
00174    }
00175 
00176         /* Skip opening quote */
00177    _s->s++;
00178    _s->len--;
00179 
00180 
00181         /* Find closing quote */
00182    end_quote = memchr(_s->s, '\"', _s->len);
00183 
00184         /* Not found, return error */
00185    if (!end_quote) {
00186       return -2;
00187    }
00188 
00189         /* Let _r point to the string without
00190          * surrounding quotes
00191          */
00192    _r->s = _s->s;
00193    _r->len = end_quote - _s->s;
00194 
00195         /* Update _s parameter to point
00196          * behind the closing quote
00197          */
00198    _s->len -= (end_quote - _s->s + 1);
00199    _s->s = end_quote + 1;
00200 
00201         /* Everything went OK */
00202    return 0;
00203 }
00204 
00205 
00206 /*!
00207  * Parse unquoted token in a parameter body
00208  * let _r point to the token and update _s
00209  * to point right behind the token
00210  */
00211 static inline int parse_token_param(str* _s, str* _r)
00212 {
00213    int i;
00214 
00215         /* There is nothing to parse,
00216          * return error
00217          */
00218    if (_s->len == 0) {
00219       return -1;
00220    }
00221 
00222         /* Save the begining of the
00223          * token in _r->s
00224          */
00225    _r->s = _s->s;
00226 
00227         /* Iterate through the
00228          * token body
00229          */
00230    for(i = 0; i < _s->len; i++) {
00231 
00232            /* All these characters
00233             * mark end of the token
00234             */
00235       switch(_s->s[i]) {
00236       case ' ':
00237       case '\t':
00238       case '\r':
00239       case '\n':
00240       case ',':
00241       case ';':
00242               /* So if you find
00243                * any of them
00244                * stop iterating
00245                */
00246          goto out;
00247       }
00248    }
00249  out:
00250    if (i == 0) {
00251       return -1;
00252         }
00253 
00254         /* Save length of the token */
00255         _r->len = i;
00256 
00257         /* Update _s parameter so it points
00258          * right behind the end of the token
00259          */
00260    _s->s = _s->s + i;
00261    _s->len -= i;
00262 
00263         /* Everything went OK */
00264    return 0;
00265 }
00266 
00267 
00268 /*!
00269  * Parse a parameter name
00270  */
00271 static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
00272 {
00273 
00274    if (!_s->s) {
00275       LM_DBG("empty parameter\n");
00276       return;
00277    }
00278 
00279    _p->name.s = _s->s;
00280 
00281    while(_s->len) {
00282       switch(_s->s[0]) {
00283       case ' ':
00284       case '\t':
00285       case '\r':
00286       case '\n':
00287       case ';':
00288       case ',':
00289       case '=':
00290          goto out;
00291       }
00292       _s->s++;
00293       _s->len--;
00294    }
00295 
00296  out:
00297    _p->name.len = _s->s - _p->name.s;
00298    
00299    switch(_c) {
00300    case CLASS_CONTACT: parse_contact_class(_h, _p); break;
00301    case CLASS_URI:     parse_uri_class(_h, _p);     break;
00302    default: break;
00303    }
00304 }
00305 
00306 
00307 
00308 
00309 
00310 /*!
00311  * Parse body of a parameter. It can be quoted string or
00312  * a single token.
00313  */
00314 static inline int parse_param_body(str* _s, param_t* _c)
00315 {
00316    if (_s->s[0] == '\"') {
00317       if (parse_quoted_param(_s, &(_c->body)) < 0) {
00318          LM_ERR("failed to parse quoted string\n");
00319          return -2;
00320       }
00321    } else {
00322       if (parse_token_param(_s, &(_c->body)) < 0) {
00323          LM_ERR("failed to parse token\n");
00324          return -3;
00325       }
00326    }
00327 
00328    return 0;
00329 }
00330 
00331 
00332 /*!
00333  * \brief Parse parameters
00334  * \param _s string containing parameters, it will be updated to point behind the parameters
00335  * \param _c class of parameters
00336  * \param _h structure that will be filled with pointer to well known parameters
00337  * \param _p linked list of parsed parameters will be stored in the variable _p is pointing to
00338  
00339  * \return 0 on success and negative number on an error
00340  */
00341 int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
00342 {
00343    param_t* t;
00344 
00345    if (!_s || !_h || !_p) {
00346       LM_ERR("invalid parameter value\n");
00347       return -1;
00348    }
00349 
00350    memset(_h, 0, sizeof(param_hooks_t));
00351    *_p = 0;
00352 
00353    if (!_s->s) { /* no parameters at all -- we're done */
00354       LM_DBG("empty uri params, skipping\n");
00355       return 0;
00356    }
00357          
00358    while(1) {
00359       t = (param_t*)pkg_malloc(sizeof(param_t));
00360       if (t == 0) {
00361          LM_ERR("no pkg memory left\n");
00362          goto error;
00363       }
00364       memset(t, 0, sizeof(param_t));
00365 
00366       parse_param_name(_s, _c, _h, t);
00367       trim_leading(_s);
00368       
00369       if (_s->len == 0) { /* The last parameter without body */
00370          t->len = t->name.len;
00371          goto ok;
00372       }
00373       
00374       if (_s->s[0] == '=') {
00375          _s->s++;
00376          _s->len--;
00377          trim_leading(_s);
00378 
00379          if (_s->len == 0) {
00380             LM_ERR("body missing\n");
00381             goto error;
00382          }
00383 
00384          if (parse_param_body(_s, t) < 0) {
00385             LM_ERR("failed to parse param body\n");
00386             goto error;
00387          }
00388 
00389          t->len = _s->s - t->name.s;
00390 
00391          trim_leading(_s);
00392          if (_s->len == 0) {
00393             goto ok;
00394          }
00395       } else {
00396          t->len = t->name.len;
00397       }
00398 
00399       if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
00400       if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
00401 
00402       if (_s->s[0] != ';') {
00403          LM_ERR("invalid character [%c] - expected ;\n", _s->s[0]);
00404          goto error;
00405       }
00406 
00407       _s->s++;
00408       _s->len--;
00409       trim_leading(_s);
00410       
00411       if (_s->len == 0) {
00412          LM_ERR("param name missing after ;\n");
00413          goto error;
00414       }
00415 
00416       t->next = *_p;
00417       *_p = t;
00418    }
00419 
00420  error:
00421    if (t) pkg_free(t);
00422    free_params(*_p);
00423    *_p = 0;
00424    return -2;
00425 
00426  ok:
00427    t->next = *_p;
00428    *_p = t;
00429    return 0;
00430 }
00431 
00432 
00433 /*!
00434  * Free linked list of parameters
00435  */
00436 static inline void do_free_params(param_t* _p, int _shm)
00437 {
00438    param_t* ptr;
00439    
00440    while(_p) {
00441       ptr = _p;
00442       _p = _p->next;
00443       if (_shm) shm_free(ptr);
00444       else pkg_free(ptr);
00445    }  
00446 }
00447 
00448 
00449 /*!
00450  * Free linked list of parameters in pkg_mem
00451  */
00452 void free_params(param_t* _p)
00453 {
00454    do_free_params(_p, 0);
00455 }
00456 
00457 
00458 /*!
00459  * Free linked list of parameters in shm_mem
00460  */
00461 void shm_free_params(param_t* _p)
00462 {
00463    do_free_params(_p, 1);
00464 }
00465 
00466 
00467 /*!
00468  * Print a parameter structure, just for debugging
00469  */
00470 static inline void print_param(FILE* _o, param_t* _p)
00471 {
00472    char* type;
00473 
00474    fprintf(_o, "---param(%p)---\n", _p);
00475    
00476    switch(_p->type) {
00477    case P_OTHER:     type = "P_OTHER";     break;
00478    case P_Q:         type = "P_Q";         break;
00479    case P_EXPIRES:   type = "P_EXPIRES";   break;
00480    case P_METHODS:   type = "P_METHODS";   break;
00481    case P_TRANSPORT: type = "P_TRANSPORT"; break;
00482    case P_LR:        type = "P_LR";        break;
00483    case P_R2:        type = "P_R2";        break;
00484    case P_MADDR:     type = "P_MADDR";     break;
00485    case P_TTL:       type = "P_TTL";       break;
00486    case P_RECEIVED:  type = "P_RECEIVED";  break;
00487    case P_DSTIP:     type = "P_DSTIP";     break;
00488    case P_DSTPORT:   type = "P_DSTPORT";   break;
00489    default:          type = "UNKNOWN";     break;
00490    }
00491    
00492    fprintf(_o, "type: %s\n", type);
00493    fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
00494    fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
00495    fprintf(_o, "len : %d\n", _p->len);
00496    fprintf(_o, "---/param---\n");
00497 }
00498 
00499 
00500 /*!
00501  * Print linked list of parameters, just for debugging
00502  */
00503 void print_params(FILE* _o, param_t* _p)
00504 {
00505    param_t* ptr;
00506    
00507    ptr = _p;
00508    while(ptr) {
00509       print_param(_o, ptr);
00510       ptr = ptr->next;
00511    }
00512 }
00513 
00514 
00515 /*!
00516  * Duplicate linked list of parameters
00517  */
00518 static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
00519 {
00520    param_t* last, *ptr, *t;
00521 
00522    if (!_n) {
00523       LM_ERR("invalid parameter value\n");
00524       return -1;
00525    }
00526    
00527    last = 0;
00528    *_n = 0;
00529    ptr = _p;
00530    while(ptr) {
00531       if (_shm) {
00532          t = (param_t*)shm_malloc(sizeof(param_t));
00533       } else {
00534          t = (param_t*)pkg_malloc(sizeof(param_t));
00535       }
00536       if (!t) {
00537          LM_ERR("no more pkg memory\n");
00538          goto err;
00539       }
00540       memcpy(t, ptr, sizeof(param_t));
00541       t->next = 0;
00542 
00543       if (!*_n) *_n = t;
00544       if (last) last->next = t;
00545       last = t;
00546 
00547       ptr = ptr->next;
00548    }
00549    return 0;
00550 
00551  err:
00552    do_free_params(*_n, _shm);
00553    return -2;
00554 }
00555 
00556 
00557 /*!
00558  * Duplicate linked list of parameters in pkg_mem
00559  */
00560 int duplicate_params(param_t** _n, param_t* _p)
00561 {
00562    return do_duplicate_params(_n, _p, 0);
00563 }
00564 
00565 
00566 /*!
00567  * Duplicate linked list of parameters in shm_mem
00568  */
00569 int shm_duplicate_params(param_t** _n, param_t* _p)
00570 {
00571    return do_duplicate_params(_n, _p, 1);
00572 }

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