parse_param.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  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. * For a license to use the ser software under conditions
  16. * other than those described here, or to purchase support for this
  17. * software, please contact iptel.org by e-mail at the following addresses:
  18. * [email protected]
  19. *
  20. * ser is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program; if not, write to the Free Software
  27. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  28. *
  29. * History:
  30. * -------
  31. * 2003-03-24 Created by janakj
  32. * 2003-04-07 shm duplication added (janakj)
  33. * 2003-04-07 URI class added (janakj)
  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. /*
  44. * Try to find out parameter name, recognized parameters
  45. * are q, expires and method
  46. */
  47. static inline void parse_contact_class(param_hooks_t* _h, param_t* _p)
  48. {
  49. if (!_p->name.s) {
  50. LOG(L_ERR, "ERROR: parse_contact_class: empty value\n");
  51. return;
  52. }
  53. switch(_p->name.s[0]) {
  54. case 'q':
  55. case 'Q':
  56. if (_p->name.len == 1) {
  57. _p->type = P_Q;
  58. _h->contact.q = _p;
  59. }
  60. break;
  61. case 'e':
  62. case 'E':
  63. if ((_p->name.len == 7) &&
  64. (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
  65. _p->type = P_EXPIRES;
  66. _h->contact.expires = _p;
  67. }
  68. break;
  69. case 'm':
  70. case 'M':
  71. if ((_p->name.len == 6) &&
  72. (!strncasecmp(_p->name.s + 1, "ethod", 5))) {
  73. _p->type = P_METHOD;
  74. _h->contact.method = _p;
  75. }
  76. break;
  77. }
  78. }
  79. /*
  80. * Try to find out parameter name, recognized parameters
  81. * are transport, lr, r2, maddr
  82. */
  83. static inline void parse_uri_class(param_hooks_t* _h, param_t* _p)
  84. {
  85. if (!_p->name.s) {
  86. LOG(L_ERR, "ERROR: parse_uri_class: empty value\n");
  87. return;
  88. }
  89. switch(_p->name.s[0]) {
  90. case 't':
  91. case 'T':
  92. if ((_p->name.len == 9) &&
  93. (!strncasecmp(_p->name.s + 1, "ransport", 8))) {
  94. _p->type = P_TRANSPORT;
  95. _h->uri.transport = _p;
  96. }
  97. break;
  98. case 'l':
  99. case 'L':
  100. if ((_p->name.len == 2) && ((_p->name.s[1] == 'r') || (_p->name.s[1] == 'R'))) {
  101. _p->type = P_LR;
  102. _h->uri.lr = _p;
  103. }
  104. break;
  105. case 'r':
  106. case 'R':
  107. if ((_p->name.len == 2) && (_p->name.s[1] == '2')) {
  108. _p->type = P_R2;
  109. _h->uri.r2 = _p;
  110. }
  111. break;
  112. case 'm':
  113. case 'M':
  114. if ((_p->name.len == 5) &&
  115. (!strncasecmp(_p->name.s + 1, "addr", 4))) {
  116. _p->type = P_MADDR;
  117. _h->uri.maddr = _p;
  118. }
  119. break;
  120. }
  121. }
  122. /*
  123. * Parse quoted string in a parameter body
  124. * return the string without quotes in _r
  125. * parameter and update _s to point behind the
  126. * closing quote
  127. */
  128. static inline int parse_quoted_param(str* _s, str* _r)
  129. {
  130. char* end_quote;
  131. /* The string must have at least
  132. * surrounding quotes
  133. */
  134. if (_s->len < 2) {
  135. return -1;
  136. }
  137. /* Skip opening quote */
  138. _s->s++;
  139. _s->len--;
  140. /* Find closing quote */
  141. end_quote = q_memchr(_s->s, '\"', _s->len);
  142. /* Not found, return error */
  143. if (!end_quote) {
  144. return -2;
  145. }
  146. /* Let _r point to the string without
  147. * surrounding quotes
  148. */
  149. _r->s = _s->s;
  150. _r->len = end_quote - _s->s;
  151. /* Update _s parameter to point
  152. * behind the closing quote
  153. */
  154. _s->len -= (end_quote - _s->s + 1);
  155. _s->s = end_quote + 1;
  156. /* Everything went OK */
  157. return 0;
  158. }
  159. /*
  160. * Parse unquoted token in a parameter body
  161. * let _r point to the token and update _s
  162. * to point right behind the token
  163. */
  164. static inline int parse_token_param(str* _s, str* _r)
  165. {
  166. int i;
  167. /* There is nothing to parse,
  168. * return error
  169. */
  170. if (_s->len == 0) {
  171. return -1;
  172. }
  173. /* Save the begining of the
  174. * token in _r->s
  175. */
  176. _r->s = _s->s;
  177. /* Iterate throught the
  178. * token body
  179. */
  180. for(i = 0; i < _s->len; i++) {
  181. /* All these characters
  182. * mark end of the token
  183. */
  184. switch(_s->s[i]) {
  185. case ' ':
  186. case '\t':
  187. case '\r':
  188. case '\n':
  189. case ',':
  190. case ';':
  191. /* So if you find
  192. * any of them
  193. * stop iterating
  194. */
  195. goto out;
  196. }
  197. }
  198. out:
  199. if (i == 0) {
  200. return -1;
  201. }
  202. /* Save length of the token */
  203. _r->len = i;
  204. /* Update _s parameter so it points
  205. * right behind the end of the token
  206. */
  207. _s->s = _s->s + i;
  208. _s->len -= i;
  209. /* Everything went OK */
  210. return 0;
  211. }
  212. /*
  213. * Parse a parameter name
  214. */
  215. static inline void parse_param_name(str* _s, pclass_t _c, param_hooks_t* _h, param_t* _p)
  216. {
  217. if (!_s->s) {
  218. DBG("DEBUG: parse_param_name: empty parameter\n");
  219. return;
  220. }
  221. _p->name.s = _s->s;
  222. while(_s->len) {
  223. switch(_s->s[0]) {
  224. case ' ':
  225. case '\t':
  226. case '\r':
  227. case '\n':
  228. case ';':
  229. case ',':
  230. case '=':
  231. goto out;
  232. }
  233. _s->s++;
  234. _s->len--;
  235. }
  236. out:
  237. _p->name.len = _s->s - _p->name.s;
  238. switch(_c) {
  239. case CLASS_CONTACT: parse_contact_class(_h, _p); break;
  240. case CLASS_URI: parse_uri_class(_h, _p); break;
  241. default: break;
  242. }
  243. }
  244. /*
  245. * Parse body of a parameter. It can be quoted string or
  246. * a single token.
  247. */
  248. static inline int parse_param_body(str* _s, param_t* _c)
  249. {
  250. if (_s->s[0] == '\"') {
  251. if (parse_quoted_param(_s, &(_c->body)) < 0) {
  252. LOG(L_ERR, "parse_param_body(): Error while parsing quoted string\n");
  253. return -2;
  254. }
  255. } else {
  256. if (parse_token_param(_s, &(_c->body)) < 0) {
  257. LOG(L_ERR, "parse_param_body(): Error while parsing token\n");
  258. return -3;
  259. }
  260. }
  261. return 0;
  262. }
  263. /*
  264. * Parse parameters
  265. * _s is string containing parameters, it will be updated to point behind the parameters
  266. * _c is class of parameters
  267. * _h is pointer to structure that will be filled with pointer to well known parameters
  268. * linked list of parsed parameters will be stored in
  269. * the variable _p is pointing to
  270. * The function returns 0 on success and negative number
  271. * on an error
  272. */
  273. int parse_params(str* _s, pclass_t _c, param_hooks_t* _h, param_t** _p)
  274. {
  275. param_t* t;
  276. if (!_s || !_h || !_p) {
  277. LOG(L_ERR, "parse_params(): Invalid parameter value\n");
  278. return -1;
  279. }
  280. memset(_h, 0, sizeof(param_hooks_t));
  281. *_p = 0;
  282. if (!_s->s) { /* no parameters at all -- we're done */
  283. DBG("DEBUG: parse_params: empty uri params, skipping\n");
  284. return 0;
  285. }
  286. while(1) {
  287. t = (param_t*)pkg_malloc(sizeof(param_t));
  288. if (t == 0) {
  289. LOG(L_ERR, "parse_params(): No memory left\n");
  290. goto error;
  291. }
  292. memset(t, 0, sizeof(param_t));
  293. parse_param_name(_s, _c, _h, t);
  294. trim_leading(_s);
  295. if (_s->len == 0) { /* The last parameter without body */
  296. goto ok;
  297. }
  298. if (_s->s[0] == '=') {
  299. _s->s++;
  300. _s->len--;
  301. trim_leading(_s);
  302. if (_s->len == 0) {
  303. LOG(L_ERR, "parse_params(): Body missing\n");
  304. goto error;
  305. }
  306. if (parse_param_body(_s, t) < 0) {
  307. LOG(L_ERR, "parse_params(): Error while parsing param body\n");
  308. goto error;
  309. }
  310. t->len = _s->s - t->name.s;
  311. trim_leading(_s);
  312. if (_s->len == 0) {
  313. goto ok;
  314. }
  315. } else {
  316. t->len = t->name.len;
  317. }
  318. if (_s->s[0] == ',') goto ok; /* To be able to parse header parameters */
  319. if (_s->s[0] == '>') goto ok; /* To be able to parse URI parameters */
  320. if (_s->s[0] != ';') {
  321. LOG(L_ERR, "parse_params(): Invalid character, ; expected\n");
  322. goto error;
  323. }
  324. _s->s++;
  325. _s->len--;
  326. trim_leading(_s);
  327. if (_s->len == 0) {
  328. LOG(L_ERR, "parse_params(): Param name missing after ;\n");
  329. goto error;
  330. }
  331. t->next = *_p;
  332. *_p = t;
  333. }
  334. error:
  335. if (t) pkg_free(t);
  336. free_params(*_p);
  337. return -2;
  338. ok:
  339. t->next = *_p;
  340. *_p = t;
  341. return 0;
  342. }
  343. /*
  344. * Free linked list of parameters
  345. */
  346. static inline void do_free_params(param_t* _p, int _shm)
  347. {
  348. param_t* ptr;
  349. while(_p) {
  350. ptr = _p;
  351. _p = _p->next;
  352. if (_shm) shm_free(ptr);
  353. else pkg_free(ptr);
  354. }
  355. }
  356. /*
  357. * Free linked list of parameters
  358. */
  359. void free_params(param_t* _p)
  360. {
  361. do_free_params(_p, 0);
  362. }
  363. /*
  364. * Free linked list of parameters
  365. */
  366. void shm_free_params(param_t* _p)
  367. {
  368. do_free_params(_p, 1);
  369. }
  370. /*
  371. * Print a parameter structure, just for debugging
  372. */
  373. static inline void print_param(FILE* _o, param_t* _p)
  374. {
  375. char* type;
  376. fprintf(_o, "---param(%p)---\n", _p);
  377. switch(_p->type) {
  378. case P_OTHER: type = "P_OTHER"; break;
  379. case P_Q: type = "P_Q"; break;
  380. case P_EXPIRES: type = "P_EXPIRES"; break;
  381. case P_METHOD: type = "P_METHOD"; break;
  382. case P_TRANSPORT: type = "P_TRANSPORT"; break;
  383. case P_LR: type = "P_LR"; break;
  384. case P_R2: type = "P_R2"; break;
  385. case P_MADDR: type = "P_MADDR"; break;
  386. default: type = "UNKNOWN"; break;
  387. }
  388. fprintf(_o, "type: %s\n", type);
  389. fprintf(_o, "name: \'%.*s\'\n", _p->name.len, _p->name.s);
  390. fprintf(_o, "body: \'%.*s\'\n", _p->body.len, _p->body.s);
  391. fprintf(_o, "len : %d\n", _p->len);
  392. fprintf(_o, "---/param---\n");
  393. }
  394. /*
  395. * Print linked list of parameters, just for debugging
  396. */
  397. void print_params(FILE* _o, param_t* _p)
  398. {
  399. param_t* ptr;
  400. ptr = _p;
  401. while(ptr) {
  402. print_param(_o, ptr);
  403. ptr = ptr->next;
  404. }
  405. }
  406. /*
  407. * Duplicate linked list of parameters
  408. */
  409. static inline int do_duplicate_params(param_t** _n, param_t* _p, int _shm)
  410. {
  411. param_t* last, *ptr, *t;
  412. if (!_n) {
  413. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  414. return -1;
  415. }
  416. last = 0;
  417. *_n = 0;
  418. ptr = _p;
  419. while(ptr) {
  420. if (_shm) {
  421. t = (param_t*)shm_malloc(sizeof(param_t));
  422. } else {
  423. t = (param_t*)pkg_malloc(sizeof(param_t));
  424. }
  425. if (!t) {
  426. LOG(L_ERR, "duplicate_params(): Invalid parameter value\n");
  427. goto err;
  428. }
  429. memcpy(t, ptr, sizeof(param_t));
  430. t->next = 0;
  431. if (!*_n) *_n = t;
  432. if (last) last->next = t;
  433. last = t;
  434. ptr = ptr->next;
  435. }
  436. return 0;
  437. err:
  438. do_free_params(*_n, _shm);
  439. return -2;
  440. }
  441. /*
  442. * Duplicate linked list of parameters
  443. */
  444. int duplicate_params(param_t** _n, param_t* _p)
  445. {
  446. return do_duplicate_params(_n, _p, 0);
  447. }
  448. /*
  449. * Duplicate linked list of parameters
  450. */
  451. int shm_duplicate_params(param_t** _n, param_t* _p)
  452. {
  453. return do_duplicate_params(_n, _p, 1);
  454. }