Coverage Report

Created: 2025-07-18 06:32

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