parse_param.c

Go to the documentation of this file.
00001 /* 
00002  * Generic Parameter Parser
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of ser, a free SIP server.
00007  *
00008  * ser 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  * ser 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  * History:
00023  * -------
00024  * 2003-03-24 Created by janakj
00025  * 2003-04-07 shm duplication added (janakj)
00026  * 2003-04-07 URI class added (janakj)
00027  */
00028 
00035 #include <string.h>
00036 #include "../str.h"
00037 #include "../ut.h"
00038 #include "../dprint.h"
00039 #include "../trim.h"
00040 #include "../mem/mem.h"
00041 #include "../mem/shm_mem.h"
00042 #include "parse_param.h"
00043 
00044 
00045 static inline void parse_event_dialog_class(param_hooks_t* h, param_t* p)
00046 {
00047 
00048         if (!p->name.s) {
00049                 LOG(L_ERR, "ERROR: parse_event_dialog_class: empty value\n");
00050                 return;
00051         }
00052         if (!h) {
00053                 LOG(L_CRIT, "BUG: parse_event_dialog_class: NULL param hook pointer\n");
00054                 return;
00055         }
00056         switch(p->name.s[0]) {
00057         case 'c':
00058         case 'C':
00059                 if ((p->name.len == 7) &&
00060                     (!strncasecmp(p->name.s + 1, "all-id", 6))) {
00061                         p->type = P_CALL_ID;
00062                         h->event_dialog.call_id = p;
00063                 }
00064                 break;
00065 
00066         case 'f':
00067         case 'F':
00068                 if ((p->name.len == 8) &&
00069                     (!strncasecmp(p->name.s + 1, "rom-tag", 7))) {
00070                         p->type = P_FROM_TAG;
00071                         h->event_dialog.from_tag = p;
00072                 }
00073                 break;
00074 
00075         case 't':
00076         case 'T':
00077                 if ((p->name.len == 6) &&
00078                     (!strncasecmp(p->name.s + 1, "o-tag", 5))) {
00079                         p->type = P_TO_TAG;
00080                         h->event_dialog.to_tag = p;
00081                 }
00082                 break;
00083 
00084         case 'i':
00085         case 'I':
00086                 if ((p->name.len == 27) &&
00087                     (!strncasecmp(p->name.s + 1, "nclude-session-description", 26))) {
00088                         p->type = P_ISD;
00089                         h->event_dialog.include_session_description = p;
00090                 }
00091                 break;
00092 
00093         case 's':
00094         case 'S':
00095                 if ((p->name.len == 3) &&
00096                     (!strncasecmp(p->name.s + 1, "la", 2))) {
00097                         p->type = P_SLA;
00098                         h->event_dialog.sla = p;
00099                 }
00100                 break;
00101 
00102         case 'm':
00103         case 'M':
00104                 if ((p->name.len == 2) &&
00105                     (!strncasecmp(p->name.s + 1, "a", 1))) {
00106                         p->type = P_MA;
00107                         h->event_dialog.ma = p;
00108                 }
00109                 break;
00110         }
00111 }
00112 
00113 
00118 static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
00119 {
00120 
00121         if (!_p->name.s) {
00122                 LOG(L_ERR, "ERROR: parse_contact_class: empty value\n");
00123                 return;
00124         }
00125         if (!_h) {
00126                 LOG(L_CRIT, "BUG: parse_contact_class: NULL param hook pointer\n");
00127                 return;
00128         }
00129         switch(_p->name.s[0]) {
00130         case 'q':
00131         case 'Q':
00132                 if (_p->name.len == 1) {
00133                         _p->type = P_Q;
00134                         _h->contact.q = _p;
00135                 }
00136                 break;
00137                 
00138         case 'e':
00139         case 'E':
00140                 if ((_p->name.len == 7) &&
00141                     (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
00142                         _p->type = P_EXPIRES;
00143                         _h->contact.expires = _p;
00144                 }
00145                 break;
00146                 
00147         case 'm':
00148         case 'M':
00149                 if ((_p->name.len == 7) &&
00150                     (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
00151                         _p->type = P_METHODS;
00152                         _h->contact.methods = _p;
00153                 }
00154                 break;
00155                 
00156         case 'r':
00157         case 'R':
00158                 if ((_p->name.len == 8) &&
00159                     (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
00160                         _p->type = P_RECEIVED;
00161                         _h->contact.received = _p;
00162                 } else if((_p->name.len == 6) &&
00163                     (!strncasecmp(_p->name.s + 1, "eg-id", 5))) {
00164                         _p->type = P_REG_ID;
00165                         _h->contact.reg_id = _p;
00166                 }
00167                 break;
00168         case '+':
00169                 if ((_p->name.len == 13) &&
00170                         (!strncasecmp(_p->name.s + 1, "sip.instance", 12))) {
00171                         _p->type = P_INSTANCE;
00172                         _h->contact.instance = _p;
00173                 }
00174                 break;
00175         }
00176 }
00177 
00178 
00183 static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
00184 {
00185 
00186         if (!_p->name.s) {
00187                 LOG(L_ERR, "ERROR: parse_uri_class: empty value\n");
00188                 return;
00189         }
00190         if (!_h) {
00191                 LOG(L_CRIT, "BUG: parse_uri_class: NULL param hook pointer\n");
00192                 return;
00193         }
00194         switch(_p->name.s[0]) {
00195         case 't':
00196         case 'T':
00197                 if ((_p->name.len == 9) &&
00198                     (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
00199                         _p->type = P_TRANSPORT;
00200                         _h->uri.transport = _p;
00201                 } else if (_p->name.len == 2) {
00202                         if (((_p->name.s[1] == 't') || (_p->name.s[1] == 'T')) &&
00203                             ((_p->name.s[2] == 'l') || (_p->name.s[2] == 'L'))) {
00204                                 _p->type = P_TTL;
00205                                 _h->uri.ttl = _p;
00206                         }
00207                 }
00208                 break;
00209 
00210         case 'l':
00211         case 'L':
00212                 if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
00213                         _p->type = P_LR;
00214                         _h->uri.lr = _p;
00215                 }
00216                 break;
00217 
00218         case 'r':
00219         case 'R':
00220                 if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
00221                         _p->type = P_R2;
00222                         _h->uri.r2 = _p;
00223                 }
00224                 break;
00225 
00226         case 'm':
00227         case 'M':
00228                 if ((_p->name.len == 5) &&
00229                     (!strncasecmp(_p->name.s + 1, "addr", 4))) {
00230                         _p->type = P_MADDR;
00231                         _h->uri.maddr = _p;
00232                 }
00233                 break;
00234                 
00235         case 'd':
00236         case 'D':
00237                 if ((_p->name.len == 5) &&
00238                     (!strncasecmp(_p->name.s + 1, "stip", 4))) {
00239                         _p->type = P_DSTIP;
00240                         _h->uri.dstip = _p;
00241                 } else if ((_p->name.len == 7) &&
00242                            (!strncasecmp(_p->name.s + 1, "stport", 6))) {
00243                         _p->type = P_DSTPORT;
00244                         _h->uri.dstport = _p;
00245                 }
00246                 break;
00247         case 'f':
00248         case 'F':
00249                 if ((_p->name.len == 4) &&
00250                     (!strncasecmp(_p->name.s + 1, "tag", 3))) {
00251                         _p->type = P_FTAG;
00252                         _h->uri.ftag = _p;
00253                 }
00254                 break;
00255         }
00256 
00257 }
00258 
00259 
00266 static inline int parse_quoted_param(str* _s, str* _r)
00267 {
00268         char* end_quote;
00269 
00270              /* The string must have at least
00271               * surrounding quotes
00272               */
00273         if (_s->len < 2) {
00274                 return -1;
00275         }
00276 
00277              /* Skip opening quote */
00278         _s->s++;
00279         _s->len--;
00280 
00281 
00282              /* Find closing quote */
00283         end_quote = q_memchr(_s->s, '\"', _s->len);
00284 
00285              /* Not found, return error */
00286         if (!end_quote) {
00287                 return -2;
00288         }
00289 
00290              /* Let _r point to the string without
00291               * surrounding quotes
00292               */
00293         _r->s = _s->s;
00294         _r->len = end_quote - _s->s;
00295 
00296              /* Update _s parameter to point
00297               * behind the closing quote
00298               */
00299         _s->len -= (end_quote - _s->s + 1);
00300         _s->s = end_quote + 1;
00301 
00302              /* Everything went OK */
00303         return 0;
00304 }
00305 
00306 
00312 static inline int parse_token_param(str* _s, str* _r)
00313 {
00314         int i;
00315 
00316              /* There is nothing to parse,
00317               * return error
00318               */
00319         if (_s->len == 0) {
00320                 return -1;
00321         }
00322 
00323              /* Save the begining of the
00324               * token in _r->s
00325               */
00326         _r->s = _s->s;
00327 
00328              /* Iterate through the
00329               * token body
00330               */
00331         for(i = 0; i < _s->len; i++) {
00332 
00333                      /* All these characters
00334                       * mark end of the token
00335                       */
00336                 switch(_s->s[i]) {
00337                 case ' ':
00338                 case '\t':
00339                 case '\r':
00340                 case '\n':
00341                 case ',':
00342                 case ';':
00343                              /* So if you find
00344                               * any of them
00345                               * stop iterating
00346                               */
00347                         goto out;
00348                 }
00349         }
00350  out:
00351         if (i == 0) {
00352                 return -1;
00353         }
00354 
00355              /* Save length of the token */
00356         _r->len = i;
00357 
00358              /* Update _s parameter so it points
00359               * right behind the end of the token
00360               */
00361         _s->s = _s->s + i;
00362         _s->len -= i;
00363 
00364              /* Everything went OK */
00365         return 0;
00366 }
00367 
00368 
00372 static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
00373 {
00374 
00375         if (!_s->s) {
00376                 DBG("DEBUG: parse_param_name: empty parameter\n");
00377                 return;
00378         }
00379 
00380         _p->name.s = _s->s;
00381 
00382         while(_s->len) {
00383                 switch(_s->s[0]) {
00384                 case ' ':
00385                 case '\t':
00386                 case '\r':
00387                 case '\n':
00388                 case ';':
00389                 case ',':
00390                 case '=':
00391                         goto out;
00392                 }
00393                 _s->s++;
00394                 _s->len--;
00395         }
00396 
00397  out:
00398         _p->name.len = _s->s - _p->name.s;
00399 
00400         switch(_c) {
00401         case CLASS_CONTACT: parse_contact_class(_h, _p); break;
00402         case CLASS_URI:     parse_uri_class(_h, _p);     break;
00403         case CLASS_EVENT_DIALOG: parse_event_dialog_class(_h, _p); break;
00404         default: break;
00405         }
00406 }
00407 
00408 
00409 
00410 
00411 
00416 static inline int parse_param_body(str* _s, param_t* _c)
00417 {
00418         if (_s->s[0] == '\"') {
00419                 if (parse_quoted_param(_s, &(_c->body)) < 0) {
00420                         LOG(L_ERR, "parse_param_body(): Error while parsing quoted string\n");
00421                         return -2;
00422                 }
00423         } else {
00424                 if (parse_token_param(_s, &(_c->body)) < 0) {
00425                         LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
00426                         return -3;
00427                 }
00428         }
00429 
00430         return 0;
00431 }
00432 
00433 
00442 inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
00443 {
00444         memset(t, 0, sizeof(param_t));
00445 
00446         parse_param_name(_s, _c, _h, t);
00447         trim_leading(_s);
00448         
00449         if (_s->len == 0) { /* The last parameter without body */
00450                 t->len = t->name.len;
00451                 goto ok;
00452         }
00453         
00454         if (_s->s[0] == '=') {
00455                 _s->s++;
00456                 _s->len--;
00457                 trim_leading(_s);
00458 
00459                 if (_s->len == 0) {
00460                     /* Be forgiving and accept parameters with missing value,
00461                      * we just set the length of parameter body to 0. */
00462                     t->body.s = _s->s;
00463                     t->body.len = 0;
00464                 } else if (parse_param_body(_s, t) < 0) {
00465                         LOG(L_ERR, "parse_params(): Error while parsing param body\n");
00466                         goto error;
00467                 }
00468 
00469                 t->len = _s->s - t->name.s;
00470 
00471                 trim_leading(_s);
00472                 if (_s->len == 0) {
00473                         goto ok;
00474                 }
00475         } else {
00476                 t->len = t->name.len;
00477         }
00478 
00479         if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
00480         if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
00481 
00482         if (_s->s[0] != ';') {
00483                 LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
00484                 goto error;
00485         }
00486 
00487         _s->s++;
00488         _s->len--;
00489         trim_leading(_s);
00490         
00491         if (_s->len == 0) {
00492                 LOG(L_ERR, "parse_params(): Param name missing after ;\n");
00493                 goto error;
00494         }
00495 
00496         return 0; /* expect more params */
00497 
00498 ok:
00499         return 1; /* done with parsing for params */
00500 error:
00501         return -1;
00502 }
00503 
00504 
00505 
00514 int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
00515 {
00516         param_t* t;
00517 
00518         if (!_s || !_p) {
00519                 LOG(L_ERR, "parse_params(): Invalid parameter value\n");
00520                 return -1;
00521         }
00522 
00523         if (_h)
00524                 memset(_h, 0, sizeof(param_hooks_t));
00525         *_p = 0;
00526 
00527         if (!_s->s) { /* no parameters at all -- we're done */
00528                 DBG("DEBUG: parse_params: empty uri params, skipping\n");
00529                 return 0;
00530         }
00531                         
00532         while(1) {
00533                 t = (param_t*)pkg_malloc(sizeof(param_t));
00534                 if (t == 0) {
00535                         LOG(L_ERR, "parse_params(): No memory left\n");
00536                         goto error;
00537                 }
00538 
00539                 switch(parse_param(_s, _c, _h, t)) {
00540                 case 0: break;
00541                 case 1: goto ok;
00542                 default: goto error;
00543                 }
00544 
00545                 t->next = *_p;
00546                 *_p = t;
00547         }
00548 
00549  error:
00550         if (t) pkg_free(t);
00551         free_params(*_p);
00552         return -2;
00553 
00554  ok:
00555         t->next = *_p;
00556         *_p = t;
00557         return 0;
00558 }
00559 
00560 
00564 static inline void do_free_params(param_t* _p, int _shm)
00565 {
00566         param_t* ptr;
00567         
00568         while(_p) {
00569                 ptr = _p;
00570                 _p = _p->next;
00571                 if (_shm) shm_free(ptr);
00572                 else pkg_free(ptr);
00573         }       
00574 }
00575 
00576 
00580 void free_params(param_t* _p)
00581 {
00582         do_free_params(_p, 0);
00583 }
00584 
00585 
00589 void shm_free_params(param_t* _p)
00590 {
00591         do_free_params(_p, 1);
00592 }
00593 
00594 
00598 static inline void print_param(FILE* _o, param_t* _p)
00599 {
00600         char* type;
00601 
00602         fprintf(_o, "---param(%p)---\n", _p);
00603         
00604         switch(_p->type) {
00605         case P_OTHER:     type = "P_OTHER";     break;
00606         case P_Q:         type = "P_Q";         break;
00607         case P_EXPIRES:   type = "P_EXPIRES";   break;
00608         case P_METHODS:   type = "P_METHODS";   break;
00609         case P_TRANSPORT: type = "P_TRANSPORT"; break;
00610         case P_LR:        type = "P_LR";        break;
00611         case P_R2:        type = "P_R2";        break;
00612         case P_MADDR:     type = "P_MADDR";     break;
00613         case P_TTL:       type = "P_TTL";       break;
00614         case P_RECEIVED:  type = "P_RECEIVED";  break;
00615         case P_DSTIP:     type = "P_DSTIP";     break;
00616         case P_DSTPORT:   type = "P_DSTPORT";   break;
00617         case P_INSTANCE:  type = "P_INSTANCE";  break;
00618         case P_FTAG:      type = "P_FTAG";      break;
00619         case P_CALL_ID:   type = "P_CALL_ID";   break;
00620         case P_FROM_TAG:  type = "P_FROM_TAG";  break;
00621         case P_TO_TAG:    type = "P_TO_TAG";    break;
00622         case P_ISD:       type = "P_ISD";       break;
00623         case P_SLA:       type = "P_SLA";       break;
00624         default:          type = "UNKNOWN";     break;
00625         }
00626         
00627         fprintf(_o, "type: %s\n", type);
00628         fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
00629         fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
00630         fprintf(_o, "len : %d\n", _p->len);
00631         fprintf(_o, "---/param---\n");
00632 }
00633 
00634 
00638 void print_params(FILE* _o, param_t* _p)
00639 {
00640         param_t* ptr;
00641         
00642         ptr = _p;
00643         while(ptr) {
00644                 print_param(_o, ptr);
00645                 ptr = ptr->next;
00646         }
00647 }
00648 
00649 
00653 static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
00654 {
00655         param_t* last, *ptr, *t;
00656 
00657         if (!_n) {
00658                 LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
00659                 return -1;
00660         }
00661         
00662         last = 0;
00663         *_n = 0;
00664         ptr = _p;
00665         while(ptr) {
00666                 if (_shm) {
00667                         t = (param_t*)shm_malloc(sizeof(param_t));
00668                 } else {
00669                         t = (param_t*)pkg_malloc(sizeof(param_t));
00670                 }
00671                 if (!t) {
00672                         LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
00673                         goto err;
00674                 }
00675                 memcpy(t, ptr, sizeof(param_t));
00676                 t->next = 0;
00677 
00678                 if (!*_n) *_n = t;
00679                 if (last) last->next = t;
00680                 last = t;
00681 
00682                 ptr = ptr->next;
00683         }
00684         return 0;
00685 
00686  err:
00687         do_free_params(*_n, _shm);
00688         return -2;
00689 }
00690 
00691 
00695 int duplicate_params(param_t** _n, param_t* _p)
00696 {
00697         return do_duplicate_params(_n, _p, 0);
00698 }
00699 
00700 
00704 int shm_duplicate_params(param_t** _n, param_t* _p)
00705 {
00706         return do_duplicate_params(_n, _p, 1);
00707 }