parse_param.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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. }
  95. }
  96. /*! \brief
  97. * Try to find out parameter name, recognized parameters
  98. * are q, expires and methods
  99. */
  100. static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
  101. {
  102. if (!_p->name.s) {
  103. LOG(L_ERR, "ERROR: parse_contact_class: empty value\n");
  104. return;
  105. }
  106. if (!_h) {
  107. LOG(L_CRIT, "BUG: parse_uri_class: NULL param hook pointer\n");
  108. return;
  109. }
  110. switch(_p->name.s[0]) {
  111. case 'q':
  112. case 'Q':
  113. if (_p->name.len == 1) {
  114. _p->type = P_Q;
  115. _h->contact.q = _p;
  116. }
  117. break;
  118. case 'e':
  119. case 'E':
  120. if ((_p->name.len == 7) &&
  121. (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
  122. _p->type = P_EXPIRES;
  123. _h->contact.expires = _p;
  124. }
  125. break;
  126. case 'm':
  127. case 'M':
  128. if ((_p->name.len == 7) &&
  129. (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
  130. _p->type = P_METHODS;
  131. _h->contact.methods = _p;
  132. }
  133. break;
  134. case 'r':
  135. case 'R':
  136. if ((_p->name.len == 8) &&
  137. (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
  138. _p->type = P_RECEIVED;
  139. _h->contact.received = _p;
  140. }
  141. break;
  142. case '+':
  143. if ((_p->name.len == 13) &&
  144. (!strncasecmp(_p->name.s + 1, "sip.instance", 12))) {
  145. _p->type = P_INSTANCE;
  146. _h->contact.instance = _p;
  147. }
  148. break;
  149. }
  150. }
  151. /*! \brief
  152. * Try to find out parameter name, recognized parameters
  153. * are transport, lr, r2, maddr
  154. */
  155. static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
  156. {
  157. if (!_p->name.s) {
  158. LOG(L_ERR, "ERROR: parse_uri_class: empty value\n");
  159. return;
  160. }
  161. if (!_h) {
  162. LOG(L_CRIT, "BUG: parse_uri_class: NULL param hook pointer\n");
  163. return;
  164. }
  165. switch(_p->name.s[0]) {
  166. case 't':
  167. case 'T':
  168. if ((_p->name.len == 9) &&
  169. (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
  170. _p->type = P_TRANSPORT;
  171. _h->uri.transport = _p;
  172. } else if (_p->name.len == 2) {
  173. if (((_p->name.s[1] == 't') || (_p->name.s[1] == 'T')) &&
  174. ((_p->name.s[2] == 'l') || (_p->name.s[2] == 'L'))) {
  175. _p->type = P_TTL;
  176. _h->uri.ttl = _p;
  177. }
  178. }
  179. break;
  180. case 'l':
  181. case 'L':
  182. if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
  183. _p->type = P_LR;
  184. _h->uri.lr = _p;
  185. }
  186. break;
  187. case 'r':
  188. case 'R':
  189. if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
  190. _p->type = P_R2;
  191. _h->uri.r2 = _p;
  192. }
  193. break;
  194. case 'm':
  195. case 'M':
  196. if ((_p->name.len == 5) &&
  197. (!strncasecmp(_p->name.s + 1, "addr", 4))) {
  198. _p->type = P_MADDR;
  199. _h->uri.maddr = _p;
  200. }
  201. break;
  202. case 'd':
  203. case 'D':
  204. if ((_p->name.len == 5) &&
  205. (!strncasecmp(_p->name.s + 1, "stip", 4))) {
  206. _p->type = P_DSTIP;
  207. _h->uri.dstip = _p;
  208. } else if ((_p->name.len == 7) &&
  209. (!strncasecmp(_p->name.s + 1, "stport", 6))) {
  210. _p->type = P_DSTPORT;
  211. _h->uri.dstport = _p;
  212. }
  213. break;
  214. case 'f':
  215. case 'F':
  216. if ((_p->name.len == 4) &&
  217. (!strncasecmp(_p->name.s + 1, "tag", 3))) {
  218. _p->type = P_FTAG;
  219. _h->uri.ftag = _p;
  220. }
  221. break;
  222. }
  223. }
  224. /*! \brief
  225. * Parse quoted string in a parameter body
  226. * return the string without quotes in _r
  227. * parameter and update _s to point behind the
  228. * closing quote
  229. */
  230. static inline int parse_quoted_param(str* _s, str* _r)
  231. {
  232. char* end_quote;
  233. /* The string must have at least
  234. * surrounding quotes
  235. */
  236. if (_s->len < 2) {
  237. return -1;
  238. }
  239. /* Skip opening quote */
  240. _s->s++;
  241. _s->len--;
  242. /* Find closing quote */
  243. end_quote = q_memchr(_s->s, '\"', _s->len);
  244. /* Not found, return error */
  245. if (!end_quote) {
  246. return -2;
  247. }
  248. /* Let _r point to the string without
  249. * surrounding quotes
  250. */
  251. _r->s = _s->s;
  252. _r->len = end_quote - _s->s;
  253. /* Update _s parameter to point
  254. * behind the closing quote
  255. */
  256. _s->len -= (end_quote - _s->s + 1);
  257. _s->s = end_quote + 1;
  258. /* Everything went OK */
  259. return 0;
  260. }
  261. /*! \brief
  262. * Parse unquoted token in a parameter body
  263. * let _r point to the token and update _s
  264. * to point right behind the token
  265. */
  266. static inline int parse_token_param(str* _s, str* _r)
  267. {
  268. int i;
  269. /* There is nothing to parse,
  270. * return error
  271. */
  272. if (_s->len == 0) {
  273. return -1;
  274. }
  275. /* Save the begining of the
  276. * token in _r->s
  277. */
  278. _r->s = _s->s;
  279. /* Iterate through the
  280. * token body
  281. */
  282. for(i = 0; i < _s->len; i++) {
  283. /* All these characters
  284. * mark end of the token
  285. */
  286. switch(_s->s[i]) {
  287. case ' ':
  288. case '\t':
  289. case '\r':
  290. case '\n':
  291. case ',':
  292. case ';':
  293. /* So if you find
  294. * any of them
  295. * stop iterating
  296. */
  297. goto out;
  298. }
  299. }
  300. out:
  301. if (i == 0) {
  302. return -1;
  303. }
  304. /* Save length of the token */
  305. _r->len = i;
  306. /* Update _s parameter so it points
  307. * right behind the end of the token
  308. */
  309. _s->s = _s->s + i;
  310. _s->len -= i;
  311. /* Everything went OK */
  312. return 0;
  313. }
  314. /*! \brief
  315. * Parse a parameter name
  316. */
  317. static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
  318. {
  319. if (!_s->s) {
  320. DBG("DEBUG: parse_param_name: empty parameter\n");
  321. return;
  322. }
  323. _p->name.s = _s->s;
  324. while(_s->len) {
  325. switch(_s->s[0]) {
  326. case ' ':
  327. case '\t':
  328. case '\r':
  329. case '\n':
  330. case ';':
  331. case ',':
  332. case '=':
  333. goto out;
  334. }
  335. _s->s++;
  336. _s->len--;
  337. }
  338. out:
  339. _p->name.len = _s->s - _p->name.s;
  340. switch(_c) {
  341. case CLASS_CONTACT: parse_contact_class(_h, _p); break;
  342. case CLASS_URI: parse_uri_class(_h, _p); break;
  343. case CLASS_EVENT_DIALOG: parse_event_dialog_class(_h, _p); break;
  344. default: break;
  345. }
  346. }
  347. /*! \brief
  348. * Parse body of a parameter. It can be quoted string or
  349. * a single token.
  350. */
  351. static inline int parse_param_body(str* _s, param_t* _c)
  352. {
  353. if (_s->s[0] == '\"') {
  354. if (parse_quoted_param(_s, &(_c->body)) < 0) {
  355. LOG(L_ERR, "parse_param_body(): Error while parsing quoted string\n");
  356. return -2;
  357. }
  358. } else {
  359. if (parse_token_param(_s, &(_c->body)) < 0) {
  360. LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
  361. return -3;
  362. }
  363. }
  364. return 0;
  365. }
  366. /*! \brief
  367. * Only parse one parameter
  368. * Returns:
  369. * t: out parameter
  370. * -1: on error
  371. * 0: success, but expect a next paramter
  372. * 1: success and exepect no more parameters
  373. */
  374. inline int parse_param(str *_s, pclass_t _c, param_hooks_t *_h, param_t *t)
  375. {
  376. memset(t, 0, sizeof(param_t));
  377. parse_param_name(_s, _c, _h, t);
  378. trim_leading(_s);
  379. if (_s->len == 0) { /* The last parameter without body */
  380. t->len = t->name.len;
  381. goto ok;
  382. }
  383. if (_s->s[0] == '=') {
  384. _s->s++;
  385. _s->len--;
  386. trim_leading(_s);
  387. if (_s->len == 0) {
  388. LOG(L_ERR, "parse_params(): Body missing\n");
  389. goto error;
  390. }
  391. if (parse_param_body(_s, t) < 0) {
  392. LOG(L_ERR, "parse_params(): Error while parsing param body\n");
  393. goto error;
  394. }
  395. t->len = _s->s - t->name.s;
  396. trim_leading(_s);
  397. if (_s->len == 0) {
  398. goto ok;
  399. }
  400. } else {
  401. t->len = t->name.len;
  402. }
  403. if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
  404. if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
  405. if (_s->s[0] != ';') {
  406. LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
  407. goto error;
  408. }
  409. _s->s++;
  410. _s->len--;
  411. trim_leading(_s);
  412. if (_s->len == 0) {
  413. LOG(L_ERR, "parse_params(): Param name missing after ;\n");
  414. goto error;
  415. }
  416. return 0; /* expect more params */
  417. ok:
  418. return 1; /* done with parsing for params */
  419. error:
  420. return -1;
  421. }
  422. /*! \brief
  423. * Parse parameters
  424. * \param _s is string containing parameters, it will be updated to point behind the parameters
  425. * \param _c is class of parameters
  426. * \param _h is pointer to structure that will be filled with pointer to well known parameters
  427. * \param the variable _p is pointing to
  428. * linked list of parsed parameters will be stored
  429. *
  430. * The function returns 0 on success and negative number
  431. * on an error
  432. */
  433. int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
  434. {
  435. param_t* t;
  436. if (!_s || !_p) {
  437. LOG(L_ERR, "parse_params(): Invalid parameter value\n");
  438. return -1;
  439. }
  440. if (_h)
  441. memset(_h, 0, sizeof(param_hooks_t));
  442. *_p = 0;
  443. if (!_s->s) { /* no parameters at all -- we're done */
  444. DBG("DEBUG: parse_params: empty uri params, skipping\n");
  445. return 0;
  446. }
  447. while(1) {
  448. t = (param_t*)pkg_malloc(sizeof(param_t));
  449. if (t == 0) {
  450. LOG(L_ERR, "parse_params(): No memory left\n");
  451. goto error;
  452. }
  453. switch(parse_param(_s, _c, _h, t)) {
  454. case 0: break;
  455. case 1: goto ok;
  456. default: goto error;
  457. }
  458. t->next = *_p;
  459. *_p = t;
  460. }
  461. error:
  462. if (t) pkg_free(t);
  463. free_params(*_p);
  464. return -2;
  465. ok:
  466. t->next = *_p;
  467. *_p = t;
  468. return 0;
  469. }
  470. /*! \brief
  471. * Free linked list of parameters
  472. */
  473. static inline void do_free_params(param_t* _p, int _shm)
  474. {
  475. param_t* ptr;
  476. while(_p) {
  477. ptr = _p;
  478. _p = _p->next;
  479. if (_shm) shm_free(ptr);
  480. else pkg_free(ptr);
  481. }
  482. }
  483. /*! \brief
  484. * Free linked list of parameters
  485. */
  486. void free_params(param_t* _p)
  487. {
  488. do_free_params(_p, 0);
  489. }
  490. /*! \brief
  491. * Free linked list of parameters
  492. */
  493. void shm_free_params(param_t* _p)
  494. {
  495. do_free_params(_p, 1);
  496. }
  497. /*! \brief
  498. * Print a parameter structure, just for debugging
  499. */
  500. static inline void print_param(FILE* _o, param_t* _p)
  501. {
  502. char* type;
  503. fprintf(_o, "---param(%p)---\n", _p);
  504. switch(_p->type) {
  505. case P_OTHER: type = "P_OTHER"; break;
  506. case P_Q: type = "P_Q"; break;
  507. case P_EXPIRES: type = "P_EXPIRES"; break;
  508. case P_METHODS: type = "P_METHODS"; break;
  509. case P_TRANSPORT: type = "P_TRANSPORT"; break;
  510. case P_LR: type = "P_LR"; break;
  511. case P_R2: type = "P_R2"; break;
  512. case P_MADDR: type = "P_MADDR"; break;
  513. case P_TTL: type = "P_TTL"; break;
  514. case P_RECEIVED: type = "P_RECEIVED"; break;
  515. case P_DSTIP: type = "P_DSTIP"; break;
  516. case P_DSTPORT: type = "P_DSTPORT"; break;
  517. case P_INSTANCE: type = "P_INSTANCE"; break;
  518. case P_FTAG: type = "P_FTAG"; break;
  519. case P_CALL_ID: type = "P_CALL_ID"; break;
  520. case P_FROM_TAG: type = "P_FROM_TAG"; break;
  521. case P_TO_TAG: type = "P_TO_TAG"; break;
  522. case P_ISD: type = "P_ISD"; break;
  523. case P_SLA: type = "P_SLA"; break;
  524. default: type = "UNKNOWN"; break;
  525. }
  526. fprintf(_o, "type: %s\n", type);
  527. fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
  528. fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
  529. fprintf(_o, "len : %d\n", _p->len);
  530. fprintf(_o, "---/param---\n");
  531. }
  532. /*! \brief
  533. * Print linked list of parameters, just for debugging
  534. */
  535. void print_params(FILE* _o, param_t* _p)
  536. {
  537. param_t* ptr;
  538. ptr = _p;
  539. while(ptr) {
  540. print_param(_o, ptr);
  541. ptr = ptr->next;
  542. }
  543. }
  544. /*! \brief
  545. * Duplicate linked list of parameters
  546. */
  547. static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
  548. {
  549. param_t* last, *ptr, *t;
  550. if (!_n) {
  551. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  552. return -1;
  553. }
  554. last = 0;
  555. *_n = 0;
  556. ptr = _p;
  557. while(ptr) {
  558. if (_shm) {
  559. t = (param_t*)shm_malloc(sizeof(param_t));
  560. } else {
  561. t = (param_t*)pkg_malloc(sizeof(param_t));
  562. }
  563. if (!t) {
  564. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  565. goto err;
  566. }
  567. memcpy(t, ptr, sizeof(param_t));
  568. t->next = 0;
  569. if (!*_n) *_n = t;
  570. if (last) last->next = t;
  571. last = t;
  572. ptr = ptr->next;
  573. }
  574. return 0;
  575. err:
  576. do_free_params(*_n, _shm);
  577. return -2;
  578. }
  579. /*! \brief
  580. * Duplicate linked list of parameters
  581. */
  582. int duplicate_params(param_t** _n, param_t* _p)
  583. {
  584. return do_duplicate_params(_n, _p, 0);
  585. }
  586. /*! \brief
  587. * Duplicate linked list of parameters
  588. */
  589. int shm_duplicate_params(param_t** _n, param_t* _p)
  590. {
  591. return do_duplicate_params(_n, _p, 1);
  592. }