Coverage Report

Created: 2025-12-03 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/opensips/parser/contact/contact.c
Line
Count
Source
1
/*
2
 * Parses one Contact in Contact HF body
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-25 Adapted to use new parameter parser (janakj)
25
 */
26
27
#include <string.h>        /* memset */
28
#include "../../mem/mem.h" /* pkg_malloc, pkg_free */
29
#include "../../dprint.h"
30
#include "../../trim.h"    /* trim_leading, trim_trailing */
31
#include "contact.h"
32
33
34
114k
#define ST1 1 /* Basic state */
35
3.19k
#define ST2 2 /* Quoted */
36
4.73k
#define ST3 3 /* Angle quoted */
37
4.98k
#define ST4 4 /* Angle quoted and quoted */
38
1.79k
#define ST5 5 /* Escape in quoted */
39
2.83k
#define ST6 6 /* Escape in angle quoted and quoted */
40
41
42
/*
43
 * Skip URI, stops when , (next contact)
44
 * or ; (parameter) is found
45
 */
46
static inline int skip_uri(str* _s)
47
30.8k
{
48
30.8k
  register int st = ST1;
49
50
2.94M
  while(_s->len) {
51
2.94M
    switch(*(_s->s)) {
52
53.4k
    case ',':
53
79.2k
    case ';':
54
79.2k
      if (st == ST1) return 0;
55
48.6k
      break;
56
57
48.6k
    case '\"':
58
4.13k
      switch(st) {
59
715
      case ST1: st = ST2; break;
60
683
      case ST2: st = ST1; break;
61
1.09k
      case ST3: st = ST4; break;
62
1.06k
      case ST4: st = ST3; break;
63
256
      case ST5: st = ST2; break;
64
330
      case ST6: st = ST4; break;
65
4.13k
      }
66
4.13k
      break;
67
68
4.13k
    case '<':
69
2.35k
      switch(st) {
70
1.32k
      case ST1: st = ST3; break;
71
12
      case ST3:
72
12
        LM_ERR("second < found\n");
73
12
        return -1;
74
196
      case ST5: st = ST2; break;
75
203
      case ST6: st = ST4; break;
76
2.35k
      }
77
2.34k
      break;
78
79
2.36k
    case '>':
80
2.36k
      switch(st) {
81
6
      case ST1:
82
6
        LM_ERR("> is first\n");
83
6
        return -2;
84
85
1.24k
      case ST3: st = ST1; break;
86
196
      case ST5: st = ST2; break;
87
198
      case ST6: st = ST4; break;
88
2.36k
      }
89
2.35k
      break;
90
91
4.39k
    case '\\':
92
4.39k
      switch(st) {
93
898
      case ST2: st = ST5; break;
94
1.42k
      case ST4: st = ST6; break;
95
247
      case ST5: st = ST2; break;
96
683
      case ST6: st = ST4; break;
97
4.39k
      }
98
4.39k
      break;
99
100
2.85M
    default: break;
101
102
2.94M
    }
103
104
2.91M
    _s->s++;
105
2.91M
    _s->len--;
106
2.91M
  }
107
108
240
  if (st != ST1) {
109
97
    LM_ERR("< or \" not closed\n");
110
97
    return -3;
111
97
  }
112
113
143
  return 0;
114
240
}
115
116
117
/*
118
 * Skip name part
119
 *
120
 * _s will be adjusted to point at the beginning
121
 * of URI
122
 */
123
static inline int skip_name(str* _s)
124
30.9k
{
125
30.9k
  char* last_wsp, *p;
126
30.9k
  int i, quoted = 0;
127
128
129
30.9k
  if (!_s) {
130
0
    LM_ERR("invalid parameter value\n");
131
0
    return -1;
132
0
  }
133
134
30.9k
  p = _s->s;
135
136
30.9k
  last_wsp = 0;
137
138
1.38M
  for(i = 0; i < _s->len; i++) {
139
1.38M
    if (!quoted) {
140
768k
      if ((*p == ' ') || (*p == '\t')) {
141
20.3k
        last_wsp = p;
142
748k
      } else {
143
748k
        if (*p == '<') {
144
1.16k
          _s->s = p;
145
1.16k
          _s->len -= i;
146
1.16k
          return 0;
147
1.16k
        }
148
149
747k
        if (*p == ':') {
150
29.6k
          if (last_wsp) {
151
12.4k
            _s->len -= last_wsp - _s->s + 1;
152
12.4k
            _s->s = last_wsp;
153
12.4k
          }
154
29.6k
          return 0;
155
29.6k
        }
156
157
717k
        if (*p == '\"') {
158
4.03k
          quoted = 1;
159
4.03k
        }
160
717k
      }
161
768k
    } else {
162
611k
      if ((*p == '\"') && (*(p-1) != '\\')) quoted = 0;
163
611k
    }
164
1.34M
    p++;
165
1.34M
  }
166
167
110
  if (quoted) {
168
14
    LM_ERR("closing quote missing in name part of Contact\n");
169
96
  } else {
170
96
    LM_ERR("error in contact, scheme separator not found\n");
171
96
  }
172
173
110
  return -1;
174
30.9k
}
175
176
177
/*
178
 * Parse contacts in a Contact HF
179
 */
180
int parse_contacts(str* _s, contact_t** _c)
181
1.07k
{
182
1.07k
  contact_t* c;
183
1.07k
  contact_t* last;
184
1.07k
  param_hooks_t hooks;
185
186
1.07k
  last = NULL;
187
188
30.9k
  while(1) {
189
    /* Allocate and clear contact structure */
190
30.9k
    c = (contact_t*)pkg_malloc(sizeof(contact_t));
191
30.9k
    if (c == 0) {
192
0
      LM_ERR("no pkg memory left\n");
193
0
      goto error;
194
0
    }
195
30.9k
    memset(c, 0, sizeof(contact_t));
196
197
30.9k
    c->name.s = _s->s;
198
199
30.9k
    if (skip_name(_s) < 0) {
200
110
      LM_ERR("failed to skip name part\n");
201
110
      goto error;
202
110
    }
203
204
30.8k
    c->uri.s = _s->s;
205
30.8k
    c->name.len = _s->s - c->name.s;
206
30.8k
    trim_trailing(&c->name);
207
208
    /* Find the end of the URI */
209
30.8k
    if (skip_uri(_s) < 0) {
210
115
      LM_ERR("failed to skip URI\n");
211
115
      goto error;
212
115
    }
213
214
30.7k
    c->uri.len = _s->s - c->uri.s; /* Calculate URI length */
215
30.7k
    trim_trailing(&(c->uri));    /* Remove any trailing spaces from URI */
216
217
    /* Remove <> if any */
218
30.7k
    if ((c->uri.len >= 2) && (c->uri.s[0] == '<') &&
219
1.09k
    (c->uri.s[c->uri.len - 1] == '>')) {
220
668
      c->uri.s++;
221
668
      c->uri.len -= 2;
222
668
    }
223
224
30.7k
    trim(&c->uri);
225
226
    /* RFC3261 grammar enforces the existence of an URI */
227
30.7k
    if (c->uri.len==0) {
228
31
      LM_ERR("Empty URI found in contact body\n");
229
31
      goto error;
230
31
    }
231
232
30.7k
    if (_s->len == 0) goto ok;
233
234
30.5k
    if (_s->s[0] == ';') {         /* Contact parameter found */
235
7.22k
      _s->s++;
236
7.22k
      _s->len--;
237
7.22k
      trim_leading(_s);
238
239
7.22k
      if (_s->len == 0) {
240
11
        LM_ERR("failed to parse params\n");
241
11
        goto error;
242
11
      }
243
244
7.21k
      if (parse_params(_s, CLASS_CONTACT, &hooks, &c->params) < 0) {
245
220
        LM_ERR("failed to parse contact parameters\n");
246
220
        goto error;
247
220
      }
248
249
6.99k
      c->q = hooks.contact.q;
250
6.99k
      c->expires = hooks.contact.expires;
251
6.99k
      c->received = hooks.contact.received;
252
6.99k
      c->methods = hooks.contact.methods;
253
6.99k
      c->instance = hooks.contact.instance;
254
255
6.99k
      if (_s->len == 0) goto ok;
256
6.99k
    }
257
258
    /* Next character is comma */
259
29.9k
    c->len = _s->s - c->name.s;
260
29.9k
    _s->s++;
261
29.9k
    _s->len--;
262
29.9k
    trim_leading(_s);
263
264
29.9k
    if (_s->len == 0) {
265
26
      LM_ERR("text after comma missing\n");
266
26
      goto error;
267
26
    }
268
269
29.8k
    if (last) {last->next=c;} else {*_c = c;}
270
29.8k
    last = c;
271
29.8k
  }
272
273
513
 error:
274
513
  if (c) free_contacts(&c);
275
513
  free_contacts(_c); /* Free any contacts created so far */
276
513
  return -1;
277
278
559
 ok:
279
559
  c->len = _s->s - c->name.s;
280
559
  if (last) {last->next=c;} else {*_c = c;}
281
559
  return 0;
282
1.07k
}
283
284
285
/*
286
 * Free list of contacts
287
 * _c is head of the list
288
 */
289
void free_contacts(contact_t** _c)
290
1.58k
{
291
1.58k
  contact_t* ptr;
292
293
32.5k
  while(*_c) {
294
30.9k
    ptr = *_c;
295
30.9k
    *_c = (*_c)->next;
296
30.9k
    if (ptr->params) {
297
6.99k
      free_params(ptr->params);
298
6.99k
    }
299
30.9k
    pkg_free(ptr);
300
30.9k
  }
301
1.58k
}
302
303
304
/*
305
 * Print list of contacts, just for debugging
306
 */
307
void log_contacts(contact_t* _c)
308
0
{
309
0
  contact_t* ptr;
310
311
0
  ptr = _c;
312
313
0
  while(ptr) {
314
0
    LM_DBG("---Contact---\n");
315
0
    LM_DBG("name    : '%.*s'\n", ptr->name.len, ptr->name.s);
316
0
    LM_DBG("URI     : '%.*s'\n", ptr->uri.len, ptr->uri.s);
317
0
    LM_DBG("instance: %p\n", ptr->instance);
318
0
    LM_DBG("q       : %p\n", ptr->q);
319
0
    LM_DBG("expires : %p\n", ptr->expires);
320
0
    LM_DBG("received: %p\n", ptr->received);
321
0
    LM_DBG("method  : %p\n", ptr->methods);
322
0
    LM_DBG("len     : %d\n", ptr->len);
323
0
    if (ptr->params) {
324
0
      print_params(ptr->params);
325
0
    }
326
0
    LM_DBG("---/Contact---\n");
327
0
    ptr = ptr->next;
328
0
  }
329
0
}