Coverage Report

Created: 2026-05-04 06:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/parser/parse_param.c
Line
Count
Source
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
152k
{
45
46
152k
  if (!_p->name.s) {
47
0
    LM_ERR("empty value\n");
48
0
    return;
49
0
  }
50
152k
  switch(_p->name.s[0]) {
51
542
  case 'q':
52
1.99k
  case 'Q':
53
1.99k
    if (_p->name.len == 1) {
54
249
      _p->type = P_Q;
55
249
      _h->contact.q = _p;
56
249
    }
57
1.99k
    break;
58
59
1.99k
  case 'e':
60
3.21k
  case 'E':
61
3.21k
    if ((_p->name.len == 7) &&
62
706
        (!strncasecmp(_p->name.s + 1, "xpires", 6))) {
63
337
      _p->type = P_EXPIRES;
64
337
      _h->contact.expires = _p;
65
337
    }
66
3.21k
    break;
67
68
3.09k
  case 'm':
69
41.1k
  case 'M':
70
41.1k
    if ((_p->name.len == 7) &&
71
22.2k
        (!strncasecmp(_p->name.s + 1, "ethods", 6))) {
72
20.6k
      _p->type = P_METHODS;
73
20.6k
      _h->contact.methods = _p;
74
20.6k
    }
75
41.1k
    break;
76
77
781
  case 'r':
78
5.38k
  case 'R':
79
5.38k
    if ((_p->name.len == 8) &&
80
3.23k
        (!strncasecmp(_p->name.s + 1, "eceived", 7))) {
81
1.56k
      _p->type = P_RECEIVED;
82
1.56k
      _h->contact.received = _p;
83
1.56k
    }
84
5.38k
    break;
85
19.7k
  case '+':
86
19.7k
    if ((_p->name.len == 13) &&
87
9.78k
        (!strncasecmp(_p->name.s + 1, "sip.instance", 12))) {
88
8.29k
      _p->type = P_INSTANCE;
89
8.29k
      _h->contact.instance = _p;
90
8.29k
    }
91
19.7k
    break;
92
152k
  }
93
152k
}
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
737
{
173
737
  char* end_quote;
174
175
       /* The string must have at least
176
        * surrounding quotes
177
        */
178
737
  if (_s->len < 2) {
179
6
    return -1;
180
6
  }
181
182
       /* Skip opening quote */
183
731
  _s->s++;
184
731
  _s->len--;
185
186
187
       /* Find closing quote */
188
731
  end_quote = q_memchr(_s->s, '\"', _s->len);
189
190
       /* Not found, return error */
191
731
  if (!end_quote) {
192
14
    return -2;
193
14
  }
194
195
       /* Let _r point to the string without
196
        * surrounding quotes
197
        */
198
717
  _r->s = _s->s;
199
717
  _r->len = end_quote - _s->s;
200
201
       /* Update _s parameter to point
202
        * behind the closing quote
203
        */
204
717
  _s->len -= (end_quote - _s->s + 1);
205
717
  _s->s = end_quote + 1;
206
207
       /* Everything went OK */
208
717
  return 0;
209
731
}
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
22.4k
{
219
22.4k
  int i;
220
221
       /* There is nothing to parse,
222
        * return error
223
        */
224
22.4k
  if (_s->len == 0) {
225
0
    return -1;
226
0
  }
227
228
       /* Save the beginning of the
229
        * token in _r->s
230
        */
231
22.4k
  _r->s = _s->s;
232
233
       /* Iterate through the
234
        * token body
235
        */
236
479k
  for(i = 0; i < _s->len; i++) {
237
238
         /* All these characters
239
          * mark end of the token
240
          */
241
479k
    switch(_s->s[i]) {
242
1.05k
    case ' ':
243
1.41k
    case '\t':
244
4.93k
    case '\r':
245
5.22k
    case '\n':
246
6.73k
    case ',':
247
22.3k
    case ';':
248
           /* So if you find
249
            * any of them
250
            * stop iterating
251
            */
252
22.3k
      goto out;
253
479k
    }
254
479k
  }
255
22.4k
 out:
256
22.4k
  if (i == 0) {
257
23
    return -1;
258
23
        }
259
260
       /* Save length of the token */
261
22.3k
        _r->len = i;
262
263
       /* Update _s parameter so it points
264
        * right behind the end of the token
265
        */
266
22.3k
  _s->s = _s->s + i;
267
22.3k
  _s->len -= i;
268
269
       /* Everything went OK */
270
22.3k
  return 0;
271
22.4k
}
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
161k
{
279
280
161k
  if (!_s->s) {
281
0
    LM_DBG("empty parameter\n");
282
0
    return;
283
0
  }
284
285
161k
  _p->name.s = _s->s;
286
287
2.48M
  while(_s->len) {
288
2.48M
    switch(_s->s[0]) {
289
1.90k
    case ' ':
290
3.52k
    case '\t':
291
4.49k
    case '\r':
292
4.72k
    case '\n':
293
134k
    case ';':
294
139k
    case ',':
295
160k
    case '=':
296
160k
      goto out;
297
2.48M
    }
298
2.31M
    _s->s++;
299
2.31M
    _s->len--;
300
2.31M
  }
301
302
161k
 out:
303
161k
  _p->name.len = _s->s - _p->name.s;
304
305
161k
  switch(_c) {
306
152k
  case CLASS_CONTACT: parse_contact_class(_h, _p); break;
307
0
  case CLASS_URI:     parse_uri_class(_h, _p);     break;
308
9.13k
  default: break;
309
161k
  }
310
161k
}
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
23.1k
{
322
23.1k
  if (_s->s[0] == '\"') {
323
737
    if (parse_quoted_param(_s, &(_c->body)) < 0) {
324
20
      LM_ERR("failed to parse quoted string\n");
325
20
      return -2;
326
20
    }
327
22.4k
  } else {
328
22.4k
    if (parse_token_param(_s, &(_c->body)) < 0) {
329
23
      LM_ERR("failed to parse token\n");
330
23
      return -3;
331
23
    }
332
22.4k
  }
333
334
23.0k
  return 0;
335
23.1k
}
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
7.55k
{
350
7.55k
  param_t* t;
351
7.55k
  param_t* last;
352
353
7.55k
  if (!_s || !_h || !_p) {
354
0
    LM_ERR("invalid parameter value\n");
355
0
    return -1;
356
0
  }
357
358
7.55k
  memset(_h, 0, sizeof(param_hooks_t));
359
7.55k
  last = NULL;
360
7.55k
  *_p = 0;
361
362
7.55k
  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
7.55k
  LM_DBG("Parsing params for:[%.*s]\n",_s->len,_s->s);
368
369
161k
  while(1) {
370
161k
    t = (param_t*)pkg_malloc(sizeof(param_t));
371
161k
    if (t == 0) {
372
0
      LM_ERR("no pkg memory left\n");
373
0
      goto error;
374
0
    }
375
161k
    memset(t, 0, sizeof(param_t));
376
377
161k
    parse_param_name(_s, _c, _h, t);
378
161k
    trim_leading(_s);
379
380
161k
    if (_s->len == 0) { /* The last parameter without body */
381
254
      t->len = t->name.len;
382
254
      goto ok;
383
254
    }
384
385
160k
    if (_s->s[0] == '=') {
386
23.1k
      _s->s++;
387
23.1k
      _s->len--;
388
23.1k
      trim_leading(_s);
389
390
23.1k
      if (_s->len == 0) {
391
15
        LM_ERR("body missing\n");
392
15
        goto error;
393
15
      }
394
395
23.1k
      if (parse_param_body(_s, t) < 0) {
396
43
        LM_ERR("failed to parse param body\n");
397
43
        goto error;
398
43
      }
399
400
23.0k
      t->len = _s->s - t->name.s;
401
402
23.0k
      trim_leading(_s);
403
23.0k
      if (_s->len == 0) {
404
66
        goto ok;
405
66
      }
406
137k
    } else {
407
137k
      t->len = t->name.len;
408
137k
    }
409
410
160k
    if (_s->s[0]==',') goto ok; /* To be able to parse header parameters */
411
154k
    if (_s->s[0]=='>') goto ok; /* To be able to parse URI parameters */
412
413
153k
    if (_s->s[0] != ';') {
414
182
      LM_ERR("invalid character, ; expected, found %c \n",_s->s[0]);
415
182
      goto error;
416
182
    }
417
418
153k
    _s->s++;
419
153k
    _s->len--;
420
153k
    trim_leading(_s);
421
422
153k
    if (_s->len == 0) {
423
32
      LM_ERR("param name missing after ;\n");
424
32
      goto error;
425
32
    }
426
427
153k
    if (last) {last->next=t;} else {*_p = t;}
428
153k
    last = t;
429
153k
  }
430
431
272
error:
432
272
  if (t) pkg_free(t);
433
272
  free_params(*_p);
434
272
  *_p = 0;
435
272
  return -2;
436
437
7.28k
ok:
438
7.28k
  if (last) {last->next=t;} else {*_p = t;}
439
7.28k
  _h->last_param = last = t;
440
7.28k
  return 0;
441
7.55k
}
442
443
444
/*
445
 * Free linked list of parameters
446
 */
447
static inline void do_free_params(param_t* _p, int _shm)
448
7.41k
{
449
7.41k
  param_t* ptr;
450
451
160k
  while(_p) {
452
152k
    ptr = _p;
453
152k
    _p = _p->next;
454
152k
    if (_shm) shm_free(ptr);
455
152k
    else pkg_free(ptr);
456
152k
  }
457
7.41k
}
458
459
460
/*
461
 * Free linked list of parameters
462
 */
463
void free_params(param_t* _p)
464
7.41k
{
465
7.41k
  do_free_params(_p, 0);
466
7.41k
}
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
}