Coverage Report

Created: 2025-07-18 06:32

/src/opensips/parser/contact/contact.c
Line
Count
Source (jump to first uncovered line)
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
0
#define ST1 1 /* Basic state */
35
0
#define ST2 2 /* Quoted */
36
0
#define ST3 3 /* Angle quoted */
37
0
#define ST4 4 /* Angle quoted and quoted */
38
0
#define ST5 5 /* Escape in quoted */
39
0
#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
0
{
48
0
  register int st = ST1;
49
50
0
  while(_s->len) {
51
0
    switch(*(_s->s)) {
52
0
    case ',':
53
0
    case ';':
54
0
      if (st == ST1) return 0;
55
0
      break;
56
57
0
    case '\"':
58
0
      switch(st) {
59
0
      case ST1: st = ST2; break;
60
0
      case ST2: st = ST1; break;
61
0
      case ST3: st = ST4; break;
62
0
      case ST4: st = ST3; break;
63
0
      case ST5: st = ST2; break;
64
0
      case ST6: st = ST4; break;
65
0
      }
66
0
      break;
67
68
0
    case '<':
69
0
      switch(st) {
70
0
      case ST1: st = ST3; break;
71
0
      case ST3:
72
0
        LM_ERR("second < found\n");
73
0
        return -1;
74
0
      case ST5: st = ST2; break;
75
0
      case ST6: st = ST4; break;
76
0
      }
77
0
      break;
78
79
0
    case '>':
80
0
      switch(st) {
81
0
      case ST1:
82
0
        LM_ERR("> is first\n");
83
0
        return -2;
84
85
0
      case ST3: st = ST1; break;
86
0
      case ST5: st = ST2; break;
87
0
      case ST6: st = ST4; break;
88
0
      }
89
0
      break;
90
91
0
    case '\\':
92
0
      switch(st) {
93
0
      case ST2: st = ST5; break;
94
0
      case ST4: st = ST6; break;
95
0
      case ST5: st = ST2; break;
96
0
      case ST6: st = ST4; break;
97
0
      }
98
0
      break;
99
100
0
    default: break;
101
102
0
    }
103
104
0
    _s->s++;
105
0
    _s->len--;
106
0
  }
107
108
0
  if (st != ST1) {
109
0
    LM_ERR("< or \" not closed\n");
110
0
    return -3;
111
0
  }
112
113
0
  return 0;
114
0
}
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
0
{
125
0
  char* last_wsp, *p;
126
0
  int i, quoted = 0;
127
128
129
0
  if (!_s) {
130
0
    LM_ERR("invalid parameter value\n");
131
0
    return -1;
132
0
  }
133
134
0
  p = _s->s;
135
136
0
  last_wsp = 0;
137
138
0
  for(i = 0; i < _s->len; i++) {
139
0
    if (!quoted) {
140
0
      if ((*p == ' ') || (*p == '\t')) {
141
0
        last_wsp = p;
142
0
      } else {
143
0
        if (*p == '<') {
144
0
          _s->s = p;
145
0
          _s->len -= i;
146
0
          return 0;
147
0
        }
148
149
0
        if (*p == ':') {
150
0
          if (last_wsp) {
151
0
            _s->len -= last_wsp - _s->s + 1;
152
0
            _s->s = last_wsp;
153
0
          }
154
0
          return 0;
155
0
        }
156
157
0
        if (*p == '\"') {
158
0
          quoted = 1;
159
0
        }
160
0
      }
161
0
    } else {
162
0
      if ((*p == '\"') && (*(p-1) != '\\')) quoted = 0;
163
0
    }
164
0
    p++;
165
0
  }
166
167
0
  if (quoted) {
168
0
    LM_ERR("closing quote missing in name part of Contact\n");
169
0
  } else {
170
0
    LM_ERR("error in contact, scheme separator not found\n");
171
0
  }
172
173
0
  return -1;
174
0
}
175
176
177
/*
178
 * Parse contacts in a Contact HF
179
 */
180
int parse_contacts(str* _s, contact_t** _c)
181
0
{
182
0
  contact_t* c;
183
0
  contact_t* last;
184
0
  param_hooks_t hooks;
185
186
0
  last = NULL;
187
188
0
  while(1) {
189
    /* Allocate and clear contact structure */
190
0
    c = (contact_t*)pkg_malloc(sizeof(contact_t));
191
0
    if (c == 0) {
192
0
      LM_ERR("no pkg memory left\n");
193
0
      goto error;
194
0
    }
195
0
    memset(c, 0, sizeof(contact_t));
196
197
0
    c->name.s = _s->s;
198
199
0
    if (skip_name(_s) < 0) {
200
0
      LM_ERR("failed to skip name part\n");
201
0
      goto error;
202
0
    }
203
204
0
    c->uri.s = _s->s;
205
0
    c->name.len = _s->s - c->name.s;
206
0
    trim_trailing(&c->name);
207
208
    /* Find the end of the URI */
209
0
    if (skip_uri(_s) < 0) {
210
0
      LM_ERR("failed to skip URI\n");
211
0
      goto error;
212
0
    }
213
214
0
    c->uri.len = _s->s - c->uri.s; /* Calculate URI length */
215
0
    trim_trailing(&(c->uri));    /* Remove any trailing spaces from URI */
216
217
    /* Remove <> if any */
218
0
    if ((c->uri.len >= 2) && (c->uri.s[0] == '<') &&
219
0
    (c->uri.s[c->uri.len - 1] == '>')) {
220
0
      c->uri.s++;
221
0
      c->uri.len -= 2;
222
0
    }
223
224
0
    trim(&c->uri);
225
226
    /* RFC3261 grammar enforces the existence of an URI */
227
0
    if (c->uri.len==0) {
228
0
      LM_ERR("Empty URI found in contact body\n");
229
0
      goto error;
230
0
    }
231
232
0
    if (_s->len == 0) goto ok;
233
234
0
    if (_s->s[0] == ';') {         /* Contact parameter found */
235
0
      _s->s++;
236
0
      _s->len--;
237
0
      trim_leading(_s);
238
239
0
      if (_s->len == 0) {
240
0
        LM_ERR("failed to parse params\n");
241
0
        goto error;
242
0
      }
243
244
0
      if (parse_params(_s, CLASS_CONTACT, &hooks, &c->params) < 0) {
245
0
        LM_ERR("failed to parse contact parameters\n");
246
0
        goto error;
247
0
      }
248
249
0
      c->q = hooks.contact.q;
250
0
      c->expires = hooks.contact.expires;
251
0
      c->received = hooks.contact.received;
252
0
      c->methods = hooks.contact.methods;
253
0
      c->instance = hooks.contact.instance;
254
255
0
      if (_s->len == 0) goto ok;
256
0
    }
257
258
    /* Next character is comma */
259
0
    c->len = _s->s - c->name.s;
260
0
    _s->s++;
261
0
    _s->len--;
262
0
    trim_leading(_s);
263
264
0
    if (_s->len == 0) {
265
0
      LM_ERR("text after comma missing\n");
266
0
      goto error;
267
0
    }
268
269
0
    if (last) {last->next=c;} else {*_c = c;}
270
0
    last = c;
271
0
  }
272
273
0
 error:
274
0
  if (c) free_contacts(&c);
275
0
  free_contacts(_c); /* Free any contacts created so far */
276
0
  return -1;
277
278
0
 ok:
279
0
  c->len = _s->s - c->name.s;
280
0
  if (last) {last->next=c;} else {*_c = c;}
281
0
  return 0;
282
0
}
283
284
285
/*
286
 * Free list of contacts
287
 * _c is head of the list
288
 */
289
void free_contacts(contact_t** _c)
290
0
{
291
0
  contact_t* ptr;
292
293
0
  while(*_c) {
294
0
    ptr = *_c;
295
0
    *_c = (*_c)->next;
296
0
    if (ptr->params) {
297
0
      free_params(ptr->params);
298
0
    }
299
0
    pkg_free(ptr);
300
0
  }
301
0
}
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
}