OSDN Git Service

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