parse_param.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. /*
  2. * $Id$
  3. *
  4. * Generic Parameter Parser
  5. *
  6. * Copyright (C) 2001-2003 FhG Fokus
  7. *
  8. * This file is part of ser, a free SIP server.
  9. *
  10. * ser is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * ser is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. *
  24. * History:
  25. * -------
  26. * 2003-03-24 Created by janakj
  27. * 2003-04-07 shm duplication added (janakj)
  28. * 2003-04-07 URI class added (janakj)
  29. */
  30. /*! \file
  31. * \brief Parser :: Generic Parameter Parser
  32. *
  33. * \ingroup parser
  34. */
  35. #include <string.h>
  36. #include "../str.h"
  37. #include "../ut.h"
  38. #include "../dprint.h"
  39. #include "../trim.h"
  40. #include "../mem/mem.h"
  41. #include "../mem/shm_mem.h"
  42. #include "parse_param.h"
  43. static inline void parse_event_dialog_class(param_hooks_t* h, param_t* p)
  44. {
  45. if (!p->name.s) {
  46. LOG(L_ERR, "ERROR: parse_event_dialog_class: empty value\n");
  47. return;
  48. }
  49. if (!h) {
  50. LOG(L_CRIT, "BUG: parse_event_dialog_class: NULL param hook pointer\n");
  51. return;
  52. }
  53. switch(p->name.s[0]) {
  54. case 'c':
  55. case 'C':
  56. if ((p->name.len == 7) &&
  57. (!strncasecmp(p->name.s + 1, "all-id", 6))) {
  58. p->type = P_CALL_ID;
  59. h->event_dialog.call_id = p;
  60. }
  61. break;
  62. case 'f':
  63. case 'F':
  64. if ((p->name.len == 8) &&
  65. (!strncasecmp(p->name.s + 1, "rom-tag", 7))) {
  66. p->type = P_FROM_TAG;
  67. h->event_dialog.from_tag = p;
  68. }
  69. break;
  70. case 't':
  71. case 'T':
  72. if ((p->name.len == 6) &&
  73. (!strncasecmp(p->name.s + 1, "o-tag", 5))) {
  74. p->type = P_TO_TAG;
  75. h->event_dialog.to_tag = p;
  76. }
  77. break;
  78. case 'i':
  79. case 'I':
  80. if ((p->name.len == 27) &&
  81. (!strncasecmp(p->name.s + 1, "nclude-session-description", 26))) {
  82. p->type = P_ISD;
  83. h->event_dialog.include_session_description = p;
  84. }
  85. break;
  86. case 's':
  87. case 'S':
  88. if ((p->name.len == 3) &&
  89. (!strncasecmp(p->name.s + 1, "la", 2))) {
  90. p->type = P_SLA;
  91. h->event_dialog.sla = p;
  92. }
  93. break;
  94. case 'm':
  95. case 'M':
  96. if ((p->name.len == 2) &&
  97. (!strncasecmp(p->name.s + 1, "a", 1))) {
  98. p->type = P_MA;
  99. h->event_dialog.ma = p;
  100. }
  101. break;
  102. }
  103. }
  104. /*! \brief
  105. * Try to find out parameter name, recognized parameters
  106. * are q, expires and methods
  107. */
  108. static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
  109. {
  110. if (!_p->name.s) {
  111. LOG(L_ERR, "ERROR: parse_contact_class: empty value\n");
  112. return;
  113. }
  114. if (!_h) {
  115. LOG(L_CRIT, "BUG: parse_uri_class: NULL param hook pointer\n");
  116. return;
  117. }
  118. switch(_p->name.s[0]) {
  119. case 'q':
  120. case 'Q':
  121. if (_p->name.len == 1) {
  122. _p->type = P_Q;
  123. _h->contact.q = _p;
  124. }
  125. break;
  126. case 'e':
  127. case 'E':
  128. if ((_p->name.len == 7) &&
  129. (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
  130. _p->type = P_EXPIRES;
  131. _h->contact.expires = _p;
  132. }
  133. break;
  134. case 'm':
  135. case 'M':
  136. if ((_p->name.len == 7) &&
  137. (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
  138. _p->type = P_METHODS;
  139. _h->contact.methods = _p;
  140. }
  141. break;
  142. case 'r':
  143. case 'R':
  144. if ((_p->name.len == 8) &&
  145. (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
  146. _p->type = P_RECEIVED;
  147. _h->contact.received = _p;
  148. }
  149. break;
  150. case '+':
  151. if ((_p->name.len == 13) &&
  152. (!strncasecmp(_p->name.s + 1, "sip.instance", 12))) {
  153. _p->type = P_INSTANCE;
  154. _h->contact.instance = _p;
  155. }
  156. break;
  157. }
  158. }
  159. /*! \brief
  160. * Try to find out parameter name, recognized parameters
  161. * are transport, lr, r2, maddr
  162. */
  163. static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
  164. {
  165. if (!_p->name.s) {
  166. LOG(L_ERR, "ERROR: parse_uri_class: empty value\n");
  167. return;
  168. }
  169. if (!_h) {
  170. LOG(L_CRIT, "BUG: parse_uri_class: NULL param hook pointer\n");
  171. return;
  172. }
  173. switch(_p->name.s[0]) {
  174. case 't':
  175. case 'T':
  176. if ((_p->name.len == 9) &&
  177. (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
  178. _p->type = P_TRANSPORT;
  179. _h->uri.transport = _p;
  180. } else if (_p->name.len == 2) {
  181. if (((_p->name.s[1] == 't') || (_p->name.s[1] == 'T')) &&
  182. ((_p->name.s[2] == 'l') || (_p->name.s[2] == 'L'))) {
  183. _p->type = P_TTL;
  184. _h->uri.ttl = _p;
  185. }
  186. }
  187. break;
  188. case 'l':
  189. case 'L':
  190. if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
  191. _p->type = P_LR;
  192. _h->uri.lr = _p;
  193. }
  194. break;
  195. case 'r':
  196. case 'R':
  197. if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
  198. _p->type = P_R2;
  199. _h->uri.r2 = _p;
  200. }
  201. break;
  202. case 'm':
  203. case 'M':
  204. if ((_p->name.len == 5) &&
  205. (!strncasecmp(_p->name.s + 1, "addr", 4))) {
  206. _p->type = P_MADDR;
  207. _h->uri.maddr = _p;
  208. }
  209. break;
  210. case 'd':
  211. case 'D':
  212. if ((_p->name.len == 5) &&
  213. (!strncasecmp(_p->name.s + 1, "stip", 4))) {
  214. _p->type = P_DSTIP;
  215. _h->uri.dstip = _p;
  216. } else if ((_p->name.len == 7) &&
  217. (!strncasecmp(_p->name.s + 1, "stport", 6))) {
  218. _p->type = P_DSTPORT;
  219. _h->uri.dstport = _p;
  220. }
  221. break;
  222. case 'f':
  223. case 'F':
  224. if ((_p->name.len == 4) &&
  225. (!strncasecmp(_p->name.s + 1, "tag", 3))) {
  226. _p->type = P_FTAG;
  227. _h->uri.ftag = _p;
  228. }
  229. break;
  230. }
  231. }
  232. /*! \brief
  233. * Parse quoted string in a parameter body
  234. * return the string without quotes in _r
  235. * parameter and update _s to point behind the
  236. * closing quote
  237. */
  238. static inline int parse_quoted_param(str* _s, str* _r)
  239. {
  240. char* end_quote;
  241. /* The string must have at least
  242. * surrounding quotes
  243. */
  244. if (_s->len < 2) {
  245. return -1;
  246. }
  247. /* Skip opening quote */
  248. _s->s++;
  249. _s->len--;
  250. /* Find closing quote */
  251. end_quote = q_memchr(_s->s, '\"', _s->len);
  252. /* Not found, return error */
  253. if (!end_quote) {
  254. return -2;
  255. }
  256. /* Let _r point to the string without
  257. * surrounding quotes
  258. */
  259. _r->s = _s->s;
  260. _r->len = end_quote - _s->s;
  261. /* Update _s parameter to point
  262. * behind the closing quote
  263. */
  264. _s->len -= (end_quote - _s->s + 1);
  265. _s->s = end_quote + 1;
  266. /* Everything went OK */
  267. return 0;
  268. }
  269. /*! \brief
  270. * Parse unquoted token in a parameter body
  271. * let _r point to the token and update _s
  272. * to point right behind the token
  273. */
  274. static inline int parse_token_param(str* _s, str* _r)
  275. {
  276. int i;
  277. /* There is nothing to parse,
  278. * return error
  279. */
  280. if (_s->len == 0) {
  281. return -1;
  282. }
  283. /* Save the begining of the
  284. * token in _r->s
  285. */
  286. _r->s = _s->s;
  287. /* Iterate through the
  288. * token body
  289. */
  290. for(i = 0; i < _s->len; i++) {
  291. /* All these characters
  292. * mark end of the token
  293. */
  294. switch(_s->s[i]) {
  295. case ' ':
  296. case '\t':
  297. case '\r':
  298. case '\n':
  299. case ',':
  300. case ';':
  301. /* So if you find
  302. * any of them
  303. * stop iterating
  304. */
  305. goto out;
  306. }
  307. }
  308. out:
  309. if (i == 0) {
  310. return -1;
  311. }
  312. /* Save length of the token */
  313. _r->len = i;
  314. /* Update _s parameter so it points
  315. * right behind the end of the token
  316. */
  317. _s->s = _s->s + i;
  318. _s->len -= i;
  319. /* Everything went OK */
  320. return 0;
  321. }
  322. /*! \brief
  323. * Parse a parameter name
  324. */
  325. static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
  326. {
  327. if (!_s->s) {
  328. DBG("DEBUG: parse_param_name: empty parameter\n");
  329. return;
  330. }
  331. _p->name.s = _s->s;
  332. while(_s->len) {
  333. switch(_s->s[0]) {
  334. case ' ':
  335. case '\t':
  336. case '\r':
  337. case '\n':
  338. case ';':
  339. case ',':
  340. case '=':
  341. goto out;
  342. }
  343. _s->s++;
  344. _s->len--;
  345. }
  346. out:
  347. _p->name.len = _s->s - _p->name.s;
  348. switch(_c) {
  349. case CLASS_CONTACT: parse_contact_class(_h, _p); break;
  350. case CLASS_URI: parse_uri_class(_h, _p); break;
  351. case CLASS_EVENT_DIALOG: parse_event_dialog_class(_h, _p); break;
  352. default: break;
  353. }
  354. }
  355. /*! \brief
  356. * Parse body of a parameter. It can be quoted string or
  357. * a single token.
  358. */
  359. static inline int parse_param_body(str* _s, param_t* _c)
  360. {
  361. if (_s->s[0] == '\"') {
  362. if (parse_quoted_param(_s, &(_c->body)) < 0) {
  363. LOG(L_ERR, "parse_param_body(): Error while parsing quoted string\n");
  364. return -2;
  365. }
  366. } else {
  367. if (parse_token_param(_s, &(_c->body)) < 0) {
  368. LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
  369. return -3;
  370. }
  371. }
  372. return 0;
  373. }
  374. /*! \brief
  375. * Only parse one parameter
  376. * Returns:
  377. * t: out parameter
  378. * -1: on error
  379. * 0: success, but expect a next paramter
  380. * 1: success and exepect no more parameters
  381. */
  382. inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
  383. {
  384. memset(t, 0, sizeof(param_t));
  385. parse_param_name(_s, _c, _h, t);
  386. trim_leading(_s);
  387. if (_s->len == 0) { /* The last parameter without body */
  388. t->len = t->name.len;
  389. goto ok;
  390. }
  391. if (_s->s[0] == '=') {
  392. _s->s++;
  393. _s->len--;
  394. trim_leading(_s);
  395. if (_s->len == 0) {
  396. /* Be forgiving and accept parameters with missing value,
  397. * we just set the length of parameter body to 0. */
  398. t->body.s = _s->s;
  399. t->body.len = 0;
  400. } else if (parse_param_body(_s, t) < 0) {
  401. LOG(L_ERR, "parse_params(): Error while parsing param body\n");
  402. goto error;
  403. }
  404. t->len = _s->s - t->name.s;
  405. trim_leading(_s);
  406. if (_s->len == 0) {
  407. goto ok;
  408. }
  409. } else {
  410. t->len = t->name.len;
  411. }
  412. if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
  413. if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
  414. if (_s->s[0] != ';') {
  415. LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
  416. goto error;
  417. }
  418. _s->s++;
  419. _s->len--;
  420. trim_leading(_s);
  421. if (_s->len == 0) {
  422. LOG(L_ERR, "parse_params(): Param name missing after ;\n");
  423. goto error;
  424. }
  425. return 0; /* expect more params */
  426. ok:
  427. return 1; /* done with parsing for params */
  428. error:
  429. return -1;
  430. }
  431. /*! \brief
  432. * Parse parameters
  433. * \param _s is string containing parameters, it will be updated to point behind the parameters
  434. * \param _c is class of parameters
  435. * \param _h is pointer to structure that will be filled with pointer to well known parameters
  436. * \param the variable _p is pointing to
  437. * linked list of parsed parameters will be stored
  438. *
  439. * The function returns 0 on success and negative number
  440. * on an error
  441. */
  442. int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
  443. {
  444. param_t* t;
  445. if (!_s || !_p) {
  446. LOG(L_ERR, "parse_params(): Invalid parameter value\n");
  447. return -1;
  448. }
  449. if (_h)
  450. memset(_h, 0, sizeof(param_hooks_t));
  451. *_p = 0;
  452. if (!_s->s) { /* no parameters at all -- we're done */
  453. DBG("DEBUG: parse_params: empty uri params, skipping\n");
  454. return 0;
  455. }
  456. while(1) {
  457. t = (param_t*)pkg_malloc(sizeof(param_t));
  458. if (t == 0) {
  459. LOG(L_ERR, "parse_params(): No memory left\n");
  460. goto error;
  461. }
  462. switch(parse_param(_s, _c, _h, t)) {
  463. case 0: break;
  464. case 1: goto ok;
  465. default: goto error;
  466. }
  467. t->next = *_p;
  468. *_p = t;
  469. }
  470. error:
  471. if (t) pkg_free(t);
  472. free_params(*_p);
  473. return -2;
  474. ok:
  475. t->next = *_p;
  476. *_p = t;
  477. return 0;
  478. }
  479. /*! \brief
  480. * Free linked list of parameters
  481. */
  482. static inline void do_free_params(param_t* _p, int _shm)
  483. {
  484. param_t* ptr;
  485. while(_p) {
  486. ptr = _p;
  487. _p = _p->next;
  488. if (_shm) shm_free(ptr);
  489. else pkg_free(ptr);
  490. }
  491. }
  492. /*! \brief
  493. * Free linked list of parameters
  494. */
  495. void free_params(param_t* _p)
  496. {
  497. do_free_params(_p, 0);
  498. }
  499. /*! \brief
  500. * Free linked list of parameters
  501. */
  502. void shm_free_params(param_t* _p)
  503. {
  504. do_free_params(_p, 1);
  505. }
  506. /*! \brief
  507. * Print a parameter structure, just for debugging
  508. */
  509. static inline void print_param(FILE* _o, param_t* _p)
  510. {
  511. char* type;
  512. fprintf(_o, "---param(%p)---\n", _p);
  513. switch(_p->type) {
  514. case P_OTHER: type = "P_OTHER"; break;
  515. case P_Q: type = "P_Q"; break;
  516. case P_EXPIRES: type = "P_EXPIRES"; break;
  517. case P_METHODS: type = "P_METHODS"; break;
  518. case P_TRANSPORT: type = "P_TRANSPORT"; break;
  519. case P_LR: type = "P_LR"; break;
  520. case P_R2: type = "P_R2"; break;
  521. case P_MADDR: type = "P_MADDR"; break;
  522. case P_TTL: type = "P_TTL"; break;
  523. case P_RECEIVED: type = "P_RECEIVED"; break;
  524. case P_DSTIP: type = "P_DSTIP"; break;
  525. case P_DSTPORT: type = "P_DSTPORT"; break;
  526. case P_INSTANCE: type = "P_INSTANCE"; break;
  527. case P_FTAG: type = "P_FTAG"; break;
  528. case P_CALL_ID: type = "P_CALL_ID"; break;
  529. case P_FROM_TAG: type = "P_FROM_TAG"; break;
  530. case P_TO_TAG: type = "P_TO_TAG"; break;
  531. case P_ISD: type = "P_ISD"; break;
  532. case P_SLA: type = "P_SLA"; break;
  533. default: type = "UNKNOWN"; break;
  534. }
  535. fprintf(_o, "type: %s\n", type);
  536. fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
  537. fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
  538. fprintf(_o, "len : %d\n", _p->len);
  539. fprintf(_o, "---/param---\n");
  540. }
  541. /*! \brief
  542. * Print linked list of parameters, just for debugging
  543. */
  544. void print_params(FILE* _o, param_t* _p)
  545. {
  546. param_t* ptr;
  547. ptr = _p;
  548. while(ptr) {
  549. print_param(_o, ptr);
  550. ptr = ptr->next;
  551. }
  552. }
  553. /*! \brief
  554. * Duplicate linked list of parameters
  555. */
  556. static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
  557. {
  558. param_t* last, *ptr, *t;
  559. if (!_n) {
  560. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  561. return -1;
  562. }
  563. last = 0;
  564. *_n = 0;
  565. ptr = _p;
  566. while(ptr) {
  567. if (_shm) {
  568. t = (param_t*)shm_malloc(sizeof(param_t));
  569. } else {
  570. t = (param_t*)pkg_malloc(sizeof(param_t));
  571. }
  572. if (!t) {
  573. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  574. goto err;
  575. }
  576. memcpy(t, ptr, sizeof(param_t));
  577. t->next = 0;
  578. if (!*_n) *_n = t;
  579. if (last) last->next = t;
  580. last = t;
  581. ptr = ptr->next;
  582. }
  583. return 0;
  584. err:
  585. do_free_params(*_n, _shm);
  586. return -2;
  587. }
  588. /*! \brief
  589. * Duplicate linked list of parameters
  590. */
  591. int duplicate_params(param_t** _n, param_t* _p)
  592. {
  593. return do_duplicate_params(_n, _p, 0);
  594. }
  595. /*! \brief
  596. * Duplicate linked list of parameters
  597. */
  598. int shm_duplicate_params(param_t** _n, param_t* _p)
  599. {
  600. return do_duplicate_params(_n, _p, 1);
  601. }