Coverage Report

Created: 2024-02-25 06:34

/src/kamailio/src/core/parser/sdp/sdp_helpr_funcs.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SDP parser helpers
3
 *
4
 * Copyright (C) 2008-2009 SOMA Networks, INC.
5
 * Copyright (C) 2010 VoIP Embedded, Inc
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *
10
 *  1. Redistributions of source code must retain the above copyright notice,
11
 *  this list of conditions and the following disclaimer.
12
 *  2. Redistributions in binary form must reproduce the above copyright
13
 *  notice, this list of conditions and the following disclaimer in the
14
 *  documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR
17
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
 * EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 *
27
 */
28
29
30
#include <stdlib.h>
31
#include "../../ut.h"
32
#include "../msg_parser.h"
33
#include "../parser_f.h"
34
#include "../parse_hname2.h"
35
#include "sdp.h"
36
37
38
static struct
39
{
40
  const char *s;
41
  int len;
42
  int is_rtp;
43
} sup_ptypes[] = {{.s = "rtp/avp", .len = 7, .is_rtp = 1},
44
    {.s = "udptl", .len = 5, .is_rtp = 0},
45
    {.s = "rtp/avpf", .len = 8, .is_rtp = 1},
46
    {.s = "rtp/savp", .len = 8, .is_rtp = 1},
47
    {.s = "rtp/savpf", .len = 9, .is_rtp = 1},
48
    {.s = "udp", .len = 3, .is_rtp = 0},
49
    {.s = "udp/bfcp", .len = 8, .is_rtp = 0},
50
    {.s = NULL, .len = 0, .is_rtp = 0}};
51
52
53
#define READ(val)                                                   \
54
2.09k
  ((unsigned int)(*(val + 0)) + ((unsigned int)(*(val + 1)) << 8) \
55
2.09k
      + ((unsigned int)(*(val + 2)) << 16)                    \
56
2.09k
      + ((unsigned int)(*(val + 3)) << 24))
57
#define advance(_ptr, _n, _str, _error)           \
58
23.3k
  do {                                          \
59
23.3k
    if((_ptr) + (_n) > (_str).s + (_str).len) \
60
23.3k
      goto _error;                          \
61
23.3k
    (_ptr) = (_ptr) + (_n);                   \
62
23.2k
  } while(0);
63
#define one_of_16(_x, _t)                                                     \
64
2.09k
  (_x == _t[0] || _x == _t[15] || _x == _t[8] || _x == _t[2] || _x == _t[3] \
65
2.09k
      || _x == _t[4] || _x == _t[5] || _x == _t[6] || _x == _t[7]       \
66
2.09k
      || _x == _t[1] || _x == _t[9] || _x == _t[10] || _x == _t[11]     \
67
2.09k
      || _x == _t[12] || _x == _t[13] || _x == _t[14])
68
#define one_of_8(_x, _t)                                                     \
69
  (_x == _t[0] || _x == _t[7] || _x == _t[1] || _x == _t[2] || _x == _t[3] \
70
      || _x == _t[4] || _x == _t[5] || _x == _t[6])
71
72
int get_mixed_part_delimiter(str *body, str *mp_delimiter)
73
1.18k
{
74
1.18k
  static unsigned int boun[16] = {0x6e756f62, 0x4e756f62, 0x6e556f62,
75
1.18k
      0x4e556f62, 0x6e754f62, 0x4e754f62, 0x6e554f62, 0x4e554f62,
76
1.18k
      0x6e756f42, 0x4e756f42, 0x6e556f42, 0x4e556f42, 0x6e754f42,
77
1.18k
      0x4e754f42, 0x6e554f42, 0x4e554f42};
78
1.18k
  static unsigned int dary[16] = {0x79726164, 0x59726164, 0x79526164,
79
1.18k
      0x59526164, 0x79724164, 0x59724164, 0x79524164, 0x59524164,
80
1.18k
      0x79726144, 0x59726144, 0x79526144, 0x59526144, 0x79724144,
81
1.18k
      0x59724144, 0x79524144, 0x59524144};
82
1.18k
  str str_type;
83
1.18k
  unsigned int x;
84
1.18k
  char *p;
85
86
87
  /* LM_DBG("<%.*s>\n",body->len,body->s); */
88
1.18k
  p = str_type.s = body->s;
89
1.18k
  str_type.len = body->len;
90
20.3k
  while(*p != ';' && p < (body->s + body->len))
91
19.1k
    advance(p, 1, str_type, error);
92
1.18k
  p++;
93
1.18k
  str_type.s = p;
94
1.18k
  str_type.len = body->len - (p - body->s);
95
  /* LM_DBG("string to parse: <%.*s>\n",str_type.len,str_type.s); */
96
  /* skip spaces and tabs if any */
97
1.57k
  while(*p == ' ' || *p == '\t')
98
1.18k
    advance(p, 1, str_type, error);
99
1.18k
  advance(p, 4, str_type, error);
100
1.15k
  x = READ(p - 4);
101
1.15k
  if(!one_of_16(x, boun))
102
199
    goto other;
103
956
  advance(p, 4, str_type, error);
104
940
  x = READ(p - 4);
105
940
  if(!one_of_16(x, dary))
106
202
    goto other;
107
108
  /* skip spaces and tabs if any */
109
1.12k
  while(*p == ' ' || *p == '\t')
110
738
    advance(p, 1, str_type, error);
111
738
  if(*p != '=') {
112
39
    LM_ERR("parse error: no = found after boundary field\n");
113
39
    goto error;
114
39
  }
115
699
  advance(p, 1, str_type, error);
116
1.26k
  while((*p == ' ' || *p == '\t') && p + 1 < str_type.s + str_type.len)
117
699
    advance(p, 1, str_type, error);
118
699
  mp_delimiter->len = str_type.len - (int)(p - str_type.s);
119
699
  mp_delimiter->s = p;
120
  /* check if the boundary value is enclosed in quotes */
121
699
  if(*p == '"' || *p == '\'') {
122
28
    if(mp_delimiter->s[mp_delimiter->len - 1] == *p) {
123
19
      mp_delimiter->s = p + 1;
124
19
      mp_delimiter->len -= 2;
125
19
      if(mp_delimiter->len <= 0) {
126
3
        LM_ERR("invalid boundary field value\n");
127
3
        goto error;
128
3
      }
129
19
    } else {
130
9
      LM_ERR("missing closing quote in boundary field value\n");
131
9
      goto error;
132
9
    }
133
28
  }
134
687
  return 1;
135
136
100
error:
137
100
  return -1;
138
401
other:
139
401
  LM_DBG("'boundary' parsing error\n");
140
401
  return -1;
141
699
}
142
143
144
/**
145
 * rfc4566:
146
 * a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
147
 */
148
int extract_rtpmap(str *body, str *rtpmap_payload, str *rtpmap_encoding,
149
    str *rtpmap_clockrate, str *rtpmap_parmas)
150
0
{
151
0
  char *cp, *cp1;
152
0
  int len;
153
154
0
  if(strncasecmp(body->s, "a=rtpmap:", 9) != 0) {
155
    /*LM_DBG("We are not pointing to an a=rtpmap: attribute =>`%.*s'\n", body->len, body->s); */
156
0
    return -1;
157
0
  }
158
159
0
  cp1 = body->s;
160
161
0
  rtpmap_payload->s = cp1 + 9; /* skip `a=rtpmap:' */
162
0
  rtpmap_payload->len =
163
0
      eat_line(rtpmap_payload->s, body->s + body->len - rtpmap_payload->s)
164
0
      - rtpmap_payload->s;
165
0
  trim_len(rtpmap_payload->len, rtpmap_payload->s, *rtpmap_payload);
166
0
  len = rtpmap_payload->len;
167
168
  /* */
169
0
  cp = eat_token_end(
170
0
      rtpmap_payload->s, rtpmap_payload->s + rtpmap_payload->len);
171
0
  rtpmap_payload->len = cp - rtpmap_payload->s;
172
0
  if(rtpmap_payload->len <= 0 || cp == rtpmap_payload->s) {
173
0
    LM_ERR("no encoding in `a=rtpmap'\n");
174
0
    return -1;
175
0
  }
176
0
  len -= rtpmap_payload->len;
177
0
  rtpmap_encoding->s = cp;
178
0
  cp = eat_space_end(rtpmap_encoding->s, rtpmap_encoding->s + len);
179
0
  len -= cp - rtpmap_encoding->s;
180
0
  if(len <= 0 || cp == rtpmap_encoding->s) {
181
0
    LM_ERR("no encoding in `a=rtpmap:'\n");
182
0
    return -1;
183
0
  }
184
185
0
  rtpmap_encoding->s = cp;
186
0
  cp1 = (char *)ser_memmem(cp, "/", len, 1);
187
0
  if(cp1 == NULL) {
188
0
    LM_ERR("invalid encoding in `a=rtpmap' at [%.*s]\n", len, cp);
189
0
    return -1;
190
0
  }
191
0
  len -= cp1 - cp;
192
0
  rtpmap_encoding->len = cp1 - cp;
193
194
0
  cp = cp1 + 1; /* skip '/' */
195
0
  len--;
196
0
  rtpmap_clockrate->s = cp;
197
0
  cp1 = (char *)ser_memmem(cp, "/", len, 1);
198
0
  if(cp1 == NULL) {
199
    /* no encoding parameters */
200
0
    rtpmap_clockrate->len = len;
201
0
    rtpmap_parmas->s = NULL;
202
0
    rtpmap_parmas->len = 0;
203
0
    return 0;
204
0
  }
205
0
  rtpmap_clockrate->len = cp1 - cp;
206
0
  len -= cp1 - cp;
207
0
  rtpmap_parmas->s = cp1 + 1; /* skip '/' */
208
0
  rtpmap_parmas->len = len - 1;
209
0
  return 0;
210
0
}
211
212
int extract_fmtp(str *body, str *fmtp_payload, str *fmtp_string)
213
0
{
214
0
  char *cp, *cp1;
215
0
  int len;
216
217
0
  if(strncasecmp(body->s, "a=fmtp:", 7) != 0) {
218
    /*LM_DBG("We are not pointing to an a=fmtp: attribute =>`%.*s'\n", body->len, body->s); */
219
0
    return -1;
220
0
  }
221
222
0
  cp1 = body->s;
223
224
0
  fmtp_payload->s = cp1 + 7; /* skip `a=fmtp:' */
225
0
  fmtp_payload->len =
226
0
      eat_line(fmtp_payload->s, body->s + body->len - fmtp_payload->s)
227
0
      - fmtp_payload->s;
228
0
  trim_len(fmtp_payload->len, fmtp_payload->s, *fmtp_payload);
229
0
  len = fmtp_payload->len;
230
231
  /* */
232
0
  cp = eat_token_end(fmtp_payload->s, fmtp_payload->s + fmtp_payload->len);
233
0
  fmtp_payload->len = cp - fmtp_payload->s;
234
0
  if(fmtp_payload->len <= 0 || cp == fmtp_payload->s) {
235
0
    LM_ERR("no encoding in `a=fmtp:'\n");
236
0
    return -1;
237
0
  }
238
0
  len -= fmtp_payload->len;
239
0
  fmtp_string->s = cp;
240
0
  cp = eat_space_end(fmtp_string->s, fmtp_string->s + len);
241
0
  len -= cp - fmtp_string->s;
242
0
  if(len <= 0 || cp == fmtp_string->s) {
243
0
    LM_ERR("no encoding in `a=fmtp:'\n");
244
0
    return -1;
245
0
  }
246
247
0
  fmtp_string->s = cp;
248
249
0
  fmtp_string->len =
250
0
      eat_line(fmtp_string->s, body->s + body->len - fmtp_string->s)
251
0
      - fmtp_string->s;
252
0
  trim_len(fmtp_string->len, fmtp_string->s, *fmtp_string);
253
254
0
  return 0;
255
0
}
256
257
258
/**
259
 * Allocate a new ice attribute
260
 */
261
static inline sdp_ice_attr_t *add_sdp_ice(sdp_stream_cell_t *_stream)
262
0
{
263
0
  sdp_ice_attr_t *ice_attr;
264
0
  int len;
265
266
0
  len = sizeof(sdp_ice_attr_t);
267
0
  ice_attr = (sdp_ice_attr_t *)pkg_malloc(len);
268
0
  if(ice_attr == NULL) {
269
0
    PKG_MEM_ERROR;
270
0
    return NULL;
271
0
  }
272
0
  memset(ice_attr, 0, len);
273
274
  /* Insert the new ice attribute */
275
0
  ice_attr->next = _stream->ice_attr;
276
0
  _stream->ice_attr = ice_attr;
277
0
  _stream->ice_attrs_num++;
278
279
0
  return ice_attr;
280
0
}
281
282
static inline sdp_ice_opt_t *add_sdp_ice_opt(sdp_stream_cell_t *_stream)
283
0
{
284
0
  sdp_ice_opt_t *ice_opt;
285
0
  int len;
286
287
0
  len = sizeof(sdp_ice_opt_t);
288
0
  ice_opt = (sdp_ice_opt_t *)pkg_malloc(len);
289
0
  if(ice_opt == NULL) {
290
0
    PKG_MEM_ERROR;
291
0
    return NULL;
292
0
  }
293
0
  memset(ice_opt, 0, len);
294
295
  /* Insert the new ice option */
296
0
  ice_opt->next = _stream->ice_opt;
297
0
  _stream->ice_opt = ice_opt;
298
0
  _stream->ice_opt_num++;
299
300
0
  return ice_opt;
301
0
}
302
303
int extract_candidate(str *body, sdp_stream_cell_t *stream)
304
0
{
305
0
  char *space, *start;
306
0
  int len, fl;
307
0
  sdp_ice_attr_t *ice_attr;
308
309
0
  if((body->len < 12) || (strncasecmp(body->s, "a=candidate:", 12) != 0)) {
310
    /*LM_DBG("We are not pointing to an a=candidate: attribute =>`%.*s'\n", body->len, body->s); */
311
0
    return -1;
312
0
  }
313
314
0
  start = body->s + 12;
315
0
  len = body->len - 12;
316
317
0
  space = memchr(start, 32, len);
318
0
  if((space == NULL) || (space - start + 3 > len) || !isdigit(*(space + 1))) {
319
0
    LM_ERR("no component in `a=candidate'\n");
320
0
    return -1;
321
0
  }
322
323
0
  fl = space - start;
324
325
0
  start = space + 1;
326
0
  len = len - (space - start + 1);
327
0
  space = memchr(start, 32, len);
328
0
  if(space == NULL) {
329
0
    LM_ERR("no component in `a=candidate'\n");
330
0
    return -1;
331
0
  }
332
333
0
  ice_attr = add_sdp_ice(stream);
334
0
  if(ice_attr == NULL) {
335
0
    LM_ERR("failed to add ice attribute\n");
336
0
    return -1;
337
0
  }
338
339
  /* currently only foundation and component-id are parsed */
340
  /* if needed, parse more */
341
0
  ice_attr->foundation.s = body->s + 12;
342
0
  ice_attr->foundation.len = fl;
343
0
  ice_attr->component_id = strtol(start, (char **)NULL, 10);
344
345
0
  return 0;
346
0
}
347
348
349
/* generic method for attribute extraction
350
 * field must has format "a=attrname:" */
351
int extract_field(str *body, str *value, str field)
352
0
{
353
0
  if(strncmp(body->s, field.s, field.len < body->len ? field.len : body->len)
354
0
      != 0) {
355
    /*LM_DBG("We are not pointing to an %.* attribute =>`%.*s'\n", field.len, field.s, body->len, body->s); */
356
0
    return -1;
357
0
  }
358
359
0
  value->s = body->s + field.len; /* skip `a=attrname:' */
360
0
  value->len = eat_line(value->s, body->s + body->len - value->s) - value->s;
361
0
  trim_len(value->len, value->s, *value);
362
363
0
  return 0;
364
0
}
365
366
int extract_ice_option(str *body, sdp_stream_cell_t *stream)
367
0
{
368
0
  sdp_ice_opt_t *ice_opt;
369
370
0
  char *ptr_src;
371
0
  int max_options =
372
0
      10;   /* protection - max options can be listed in one line */
373
0
  int length = 0; /* each option length */
374
375
  /* a=ice-options: */
376
0
  if((body->len < 14) || (strncasecmp(body->s, ICE_OPTIONS, 14) != 0))
377
0
    return -1;
378
379
0
  ptr_src = body->s + 14;
380
0
  if(*ptr_src == 32)
381
0
    ptr_src++; /* if starts with a space, skip it */
382
383
  /* identify all existing ICE options, if they are listed in one row */
384
0
  while(*ptr_src && *ptr_src != '\r' && *ptr_src != '\n'
385
0
      && max_options-- > 0) {
386
0
    while(*ptr_src != 32 && *ptr_src && *ptr_src != '\r'
387
0
        && *ptr_src != '\n') {
388
0
      length++;
389
0
      ptr_src++;
390
0
    }
391
392
0
    ice_opt = add_sdp_ice_opt(stream);
393
0
    if(ice_opt == NULL) {
394
0
      LM_ERR("failed to add ice option\n");
395
0
      return -1;
396
0
    }
397
398
0
    ice_opt->option.s = ptr_src - length;
399
0
    ice_opt->option.len = length;
400
0
    trim_len(ice_opt->option.len, ice_opt->option.s, ice_opt->option);
401
402
0
    length = 0;
403
0
    if(*ptr_src == 32)
404
0
      ptr_src++; /* skip space */
405
0
  }
406
407
0
  return 0;
408
0
}
409
410
int extract_ptime(str *body, str *ptime)
411
0
{
412
0
  static const str field = str_init("a=ptime:");
413
0
  return extract_field(body, ptime, field);
414
0
}
415
416
int extract_accept_types(str *body, str *accept_types)
417
0
{
418
0
  static const str field = str_init("a=accept-types:");
419
0
  return extract_field(body, accept_types, field);
420
0
}
421
422
int extract_accept_wrapped_types(str *body, str *accept_wrapped_types)
423
0
{
424
0
  static const str field = str_init("a=accept-wrapped-types:");
425
0
  return extract_field(body, accept_wrapped_types, field);
426
0
}
427
428
int extract_max_size(str *body, str *max_size)
429
0
{
430
0
  static const str field = str_init("a=max-size:");
431
0
  return extract_field(body, max_size, field);
432
0
}
433
434
int extract_path(str *body, str *path)
435
0
{
436
0
  static const str field = str_init("a=path:");
437
0
  return extract_field(body, path, field);
438
0
}
439
440
int extract_rtcp(str *body, str *rtcp)
441
0
{
442
0
  static const str field = str_init("a=rtcp:");
443
0
  return extract_field(body, rtcp, field);
444
0
}
445
446
int extract_sendrecv_mode(str *body, str *sendrecv_mode, int *is_on_hold)
447
0
{
448
0
  char *cp1;
449
450
0
  cp1 = body->s;
451
0
  if(!((strncasecmp(cp1, "a=sendrecv", 10) == 0)
452
0
         || (strncasecmp(cp1, "a=recvonly", 10) == 0))) {
453
0
    if((strncasecmp(cp1, "a=inactive", 10) == 0)
454
0
        || (strncasecmp(cp1, "a=sendonly", 10) == 0)) {
455
0
      *is_on_hold = RFC3264_HOLD;
456
0
    } else {
457
0
      return -1;
458
0
    }
459
0
  }
460
461
0
  sendrecv_mode->s = body->s + 2; /* skip `a=' */
462
0
  sendrecv_mode->len =
463
0
      8; /* we know the length and therefore we don't need to overkill */
464
  /*
465
  sendrecv_mode->len = eat_line(sendrecv_mode->s, body->s + body->len -
466
    sendrecv_mode->s) - sendrecv_mode->s;
467
  trim_len(sendrecv_mode->len, sendrecv_mode->s, *sendrecv_mode);
468
  */
469
470
0
  return 0;
471
0
}
472
473
int extract_bwidth(str *body, str *bwtype, str *bwwitdth)
474
0
{
475
0
  char *cp, *cp1;
476
0
  int len;
477
478
0
  cp1 = NULL;
479
0
  for(cp = body->s; (len = body->s + body->len - cp) > 0;) {
480
0
    cp1 = (char *)ser_memmem(cp, "b=", len, 2);
481
0
    if(cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
482
0
      break;
483
0
    cp = cp1 + 2;
484
0
  }
485
0
  if(cp1 == NULL)
486
0
    return -1;
487
488
0
  bwtype->s = cp1 + 2;
489
0
  bwtype->len =
490
0
      eat_line(bwtype->s, body->s + body->len - bwtype->s) - bwtype->s;
491
0
  trim_len(bwtype->len, bwtype->s, *bwtype);
492
493
0
  cp = bwtype->s;
494
0
  len = bwtype->len;
495
0
  cp1 = (char *)ser_memmem(cp, ":", len, 1);
496
0
  len -= cp1 - cp;
497
0
  if(len <= 0) {
498
0
    LM_ERR("invalid encoding in `b=%.*s'\n", bwtype->len, bwtype->s);
499
0
    return -1;
500
0
  }
501
0
  bwtype->len = cp1 - cp;
502
503
  /* skip ':' */
504
0
  bwwitdth->s = cp1 + 1;
505
0
  bwwitdth->len = len - 1;
506
507
0
  return 0;
508
0
}
509
510
int extract_mediaip(str *body, str *mediaip, int *pf, char *line)
511
0
{
512
0
  char *cp, *cp1;
513
0
  int len;
514
515
0
  cp1 = NULL;
516
0
  for(cp = body->s; (len = body->s + body->len - cp) > 0;) {
517
0
    cp1 = (char *)ser_memmem(cp, line, len, 2);
518
0
    if(cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
519
0
      break;
520
0
    cp = cp1 + 2;
521
0
  }
522
0
  if(cp1 == NULL)
523
0
    return -1;
524
525
0
  mediaip->s = cp1 + 2;
526
0
  mediaip->len =
527
0
      eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s;
528
0
  trim_len(mediaip->len, mediaip->s, *mediaip);
529
0
  if(mediaip->len == 0) {
530
0
    LM_ERR("no [%s] line in SDP\n", line);
531
0
    return -1;
532
0
  }
533
534
  /* search reverse for IP[4|6] in c=/o= line */
535
0
  cp = (char *)ser_memrmem(mediaip->s, " IP", mediaip->len, 3);
536
0
  if(cp == NULL) {
537
0
    LM_ERR("no `IP[4|6]' in `%s' field\n", line);
538
0
    return -1;
539
0
  }
540
  /* safety checks:
541
   * - for length, at least 6: ' IP[4|6] x...'
542
   * - white space after
543
   */
544
0
  if(cp + 6 > mediaip->s + mediaip->len && cp[4] != ' ') {
545
0
    LM_ERR("invalid content for `%s' line\n", line);
546
0
    return -1;
547
0
  }
548
0
  switch(cp[3]) {
549
0
    case '4':
550
0
      *pf = AF_INET;
551
0
      break;
552
0
    case '6':
553
0
      *pf = AF_INET6;
554
0
      break;
555
0
    default:
556
0
      LM_ERR("invalid addrtype IPx for `%s' line\n", line);
557
0
      return -1;
558
0
  }
559
0
  cp += 5;
560
561
  /* next token is the IP address */
562
0
  cp = eat_space_end(cp, mediaip->s + mediaip->len);
563
0
  len = eat_token_end(cp, mediaip->s + mediaip->len) - cp;
564
0
  mediaip->s = cp;
565
0
  mediaip->len = len;
566
567
0
  if(mediaip->len == 0) {
568
0
    LM_ERR("no `IP[4|6]' address in `%s' field\n", line);
569
0
    return -1;
570
0
  }
571
572
0
  LM_DBG("located IP address [%.*s] in `%s' field\n", mediaip->len,
573
0
      mediaip->s, line);
574
0
  return 1;
575
0
}
576
577
int extract_media_attr(str *body, str *mediamedia, str *mediaport,
578
    str *mediatransport, str *mediapayload, int *is_rtp)
579
0
{
580
0
  char *cp, *cp1;
581
0
  int len, i;
582
583
0
  cp1 = NULL;
584
0
  for(cp = body->s; (len = body->s + body->len - cp) > 0;) {
585
0
    cp1 = (char *)ser_memmem(cp, "m=", len, 2);
586
0
    if(cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r')
587
0
      break;
588
0
    cp = cp1 + 2;
589
0
  }
590
0
  if(cp1 == NULL) {
591
0
    LM_ERR("no `m=' in SDP\n");
592
0
    return -1;
593
0
  }
594
0
  mediaport->s = cp1 + 2; /* skip `m=' */
595
0
  mediaport->len = eat_line(mediaport->s, body->s + body->len - mediaport->s)
596
0
           - mediaport->s;
597
0
  trim_len(mediaport->len, mediaport->s, *mediaport);
598
599
0
  mediapayload->len = mediaport->len;
600
0
  mediamedia->s = mediaport->s;
601
602
603
  /* Skip media supertype and spaces after it */
604
0
  cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
605
0
  mediaport->len -= cp - mediaport->s;
606
0
  mediamedia->len = mediapayload->len - mediaport->len;
607
0
  if(mediaport->len <= 0 || cp == mediaport->s) {
608
0
    LM_ERR("no port in `m='\n");
609
0
    return -1;
610
0
  }
611
0
  mediaport->s = cp;
612
613
0
  cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len);
614
0
  mediaport->len -= cp - mediaport->s;
615
0
  if(mediaport->len <= 0 || cp == mediaport->s) {
616
0
    LM_ERR("no port in `m='\n");
617
0
    return -1;
618
0
  }
619
620
  /* Extract port */
621
0
  mediaport->s = cp;
622
0
  cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len);
623
0
  mediatransport->len = mediaport->len - (cp - mediaport->s);
624
0
  if(mediatransport->len <= 0 || cp == mediaport->s) {
625
0
    LM_ERR("no port in `m='\n");
626
0
    return -1;
627
0
  }
628
0
  mediatransport->s = cp;
629
0
  mediaport->len = cp - mediaport->s;
630
631
  /* Skip spaces after port */
632
0
  cp = eat_space_end(
633
0
      mediatransport->s, mediatransport->s + mediatransport->len);
634
0
  mediatransport->len -= cp - mediatransport->s;
635
0
  if(mediatransport->len <= 0 || cp == mediatransport->s) {
636
0
    LM_ERR("no protocol type in `m='\n");
637
0
    return -1;
638
0
  }
639
  /* Extract protocol type */
640
0
  mediatransport->s = cp;
641
0
  cp = eat_token_end(
642
0
      mediatransport->s, mediatransport->s + mediatransport->len);
643
0
  if(cp == mediatransport->s) {
644
0
    LM_ERR("no protocol type in `m='\n");
645
0
    return -1;
646
0
  }
647
0
  mediatransport->len = cp - mediatransport->s;
648
649
0
  mediapayload->s = mediatransport->s + mediatransport->len;
650
0
  mediapayload->len -= mediapayload->s - mediamedia->s;
651
0
  cp = eat_space_end(mediapayload->s, mediapayload->s + mediapayload->len);
652
0
  mediapayload->len -= cp - mediapayload->s;
653
0
  mediapayload->s = cp;
654
655
0
  for(i = 0; sup_ptypes[i].s != NULL; i++)
656
0
    if(mediatransport->len == sup_ptypes[i].len
657
0
        && strncasecmp(mediatransport->s, sup_ptypes[i].s,
658
0
               mediatransport->len)
659
0
               == 0) {
660
0
      *is_rtp = sup_ptypes[i].is_rtp;
661
0
      return 0;
662
0
    }
663
  /* Unproxyable protocol type. Generally it isn't error. */
664
0
  return 0;
665
0
}
666
667
int extract_sess_version(str *oline, str *sess_version)
668
0
{
669
670
0
  char *cp0 = NULL;
671
0
  char *cp = NULL;
672
0
  int len = 0;
673
0
  char ws = ' ';
674
0
  int i = 0;
675
676
  /*
677
  "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5" CR LF
678
  "o=W 1 2 IN IP4 0.0.0.0" CR LF -> 24
679
  "o=W 1 2 IN IP6 ::1" CR LF -> 20
680
  "o=W 1 2 X Y Z" CR LF -> 15
681
  */
682
0
  if(oline->s == NULL || oline->len < 15) {
683
0
    LM_ERR("invalid o -line\n");
684
0
    return -1;
685
0
  }
686
687
0
  if(sess_version == NULL) {
688
0
    LM_ERR("invalid result pointer\n");
689
0
    return -1;
690
0
  }
691
692
0
  LM_DBG("oline(%d): >%.*s<\n", oline->len, oline->len, oline->s);
693
694
  // jump over o=
695
0
  cp = oline->s + 2;
696
0
  len = oline->len - 2;
697
698
  // find whitespace 3 times
699
0
  do {
700
0
    cp0 = cp;
701
    //LM_DBG("loop %d: >%.*s<\n", len, len, cp0);
702
703
0
    cp = (char *)ser_memmem(cp0, &ws, len, 1);
704
0
    if(cp == NULL) {
705
0
      break;
706
0
    }
707
708
    //LM_DBG("cp0: %p cp: %p (%ld)\n", cp0, cp, cp-cp0);
709
0
    len -= cp - cp0;
710
711
    // step over whitespace
712
0
    if(len > 0) {
713
0
      cp++;
714
0
      len--;
715
0
    }
716
717
0
    i++;
718
0
  } while(len < oline->len && i < 3);
719
720
0
  len = cp - cp0 - 1;
721
0
  LM_DBG("end %d: >%.*s<\n", len, len, cp0);
722
723
0
  sess_version->s = cp0;
724
0
  sess_version->len = len;
725
726
0
  if(!isdigit(*cp0)) {
727
0
    LM_WARN("not digit >%.*s<\n", len, cp0);
728
0
  }
729
730
0
  return 1;
731
0
}
732
733
734
/*
735
 * Auxiliary for some functions.
736
 * Returns pointer to first character of found line, or NULL if no such line.
737
 */
738
739
char *find_sdp_line(char *p, char *plimit, char linechar)
740
0
{
741
0
  static char linehead[3] = "x=";
742
0
  char *cp, *cp1;
743
0
  linehead[0] = linechar;
744
  /* Iterate through body */
745
0
  cp = p;
746
0
  for(;;) {
747
0
    if(cp >= plimit)
748
0
      return NULL;
749
0
    cp1 = ser_memmem(cp, linehead, plimit - cp, 2);
750
0
    if(cp1 == NULL)
751
0
      return NULL;
752
    /*
753
     * As it is body, we assume it has previous line and we can
754
     * lookup previous character.
755
     */
756
0
    if(cp1[-1] == '\n' || cp1[-1] == '\r')
757
0
      return cp1;
758
    /*
759
     * Having such data, but not at line beginning.
760
     * Skip them and reiterate. ser_memmem() will find next
761
     * occurrence.
762
     */
763
0
    if(plimit - cp1 < 2)
764
0
      return NULL;
765
0
    cp = cp1 + 2;
766
0
  }
767
0
}
768
769
770
/* This function assumes p points to a line of requested type. */
771
char *find_next_sdp_line(char *p, char *plimit, char linechar, char *defptr)
772
0
{
773
0
  char *t;
774
0
  if(p >= plimit || plimit - p < 3)
775
0
    return defptr;
776
0
  t = find_sdp_line(p + 2, plimit, linechar);
777
0
  return t ? t : defptr;
778
0
}
779
780
781
/* Find first SDP line starting with linechar. Return defptr if not found */
782
char *find_first_sdp_line(
783
    char *pstart, char *plimit, char linechar, char *defptr)
784
0
{
785
0
  char *t;
786
0
  if(pstart >= plimit || plimit - pstart < 3)
787
0
    return defptr;
788
0
  t = find_sdp_line(pstart, plimit, linechar);
789
0
  return t ? t : defptr;
790
0
}
791
792
793
/* returns pointer to next header line, and fill hdr_f ;
794
 * if at end of header returns pointer to the last crlf  (always buf)*/
795
char *get_sdp_hdr_field(char *buf, char *end, struct hdr_field *hdr)
796
4.42k
{
797
798
4.42k
  char *tmp;
799
4.42k
  char *match;
800
801
4.42k
  if((*buf) == '\n' || (*buf) == '\r') {
802
    /* double crlf or lflf or crcr */
803
1.20k
    hdr->type = HDR_EOH_T;
804
1.20k
    return buf;
805
1.20k
  }
806
807
3.22k
  tmp = parse_hname2(buf, end, hdr);
808
3.22k
  if(hdr->type == HDR_ERROR_T) {
809
94
    LM_ERR("bad header\n");
810
94
    goto error;
811
94
  }
812
813
  /* eliminate leading whitespace */
814
3.13k
  tmp = eat_lws_end(tmp, end);
815
3.13k
  if(tmp >= end) {
816
34
    LM_ERR("hf empty\n");
817
34
    goto error;
818
34
  }
819
820
  /* just skip over it */
821
3.09k
  hdr->body.s = tmp;
822
  /* find end of header */
823
  /* find lf */
824
4.20k
  do {
825
4.20k
    match = memchr(tmp, '\n', end - tmp);
826
4.20k
    if(match) {
827
4.16k
      match++;
828
4.16k
    } else {
829
44
      LM_ERR("bad body for <%.*s>(%d)\n", hdr->name.len, hdr->name.s,
830
44
          hdr->type);
831
44
      tmp = end;
832
44
      goto error;
833
44
    }
834
4.16k
    tmp = match;
835
4.16k
  } while(match < end && ((*match == ' ') || (*match == '\t')));
836
3.05k
  tmp = match;
837
3.05k
  hdr->body.len = match - hdr->body.s;
838
839
  /* jku: if \r covered by current length, shrink it */
840
3.05k
  trim_r(hdr->body);
841
3.05k
  hdr->len = tmp - hdr->name.s;
842
3.05k
  return tmp;
843
172
error:
844
172
  LM_DBG("error exit\n");
845
172
  hdr->type = HDR_ERROR_T;
846
172
  hdr->len = tmp - hdr->name.s;
847
172
  return tmp;
848
3.09k
}
849
850
851
char *find_sdp_line_delimiter(char *p, char *plimit, str delimiter)
852
3.15k
{
853
3.15k
  static char delimiterhead[3] = "--";
854
3.15k
  char *cp, *cp1;
855
  /* Iterate through body */
856
3.15k
  cp = p;
857
14.7k
  for(;;) {
858
14.7k
    if(cp >= plimit)
859
0
      return NULL;
860
15.9k
    for(;;) {
861
15.9k
      cp1 = ser_memmem(cp, delimiterhead, plimit - cp, 2);
862
15.9k
      if(cp1 == NULL)
863
614
        return NULL;
864
      /* We matched '--',
865
       * now let's match the boundary delimiter */
866
15.3k
      if(cp1 + 2 + delimiter.len >= plimit)
867
56
        return NULL;
868
15.3k
      if(strncmp(cp1 + 2, delimiter.s, delimiter.len) == 0)
869
14.0k
        break;
870
1.25k
      else
871
1.25k
        cp = cp1 + 2 + delimiter.len;
872
15.3k
    }
873
14.0k
    if(cp1[-1] == '\n' || cp1[-1] == '\r')
874
2.48k
      return cp1;
875
11.5k
    if(plimit - cp1 < 2 + delimiter.len)
876
0
      return NULL;
877
11.5k
    cp = cp1 + 2 + delimiter.len;
878
11.5k
  }
879
3.15k
}
880
881
882
/*
883
 * This function assumes p points to a delimiter type line.
884
 */
885
char *find_next_sdp_line_delimiter(
886
    char *p, char *plimit, str delimiter, char *defptr)
887
2.46k
{
888
2.46k
  char *t;
889
2.46k
  if(p >= plimit || plimit - p < 3)
890
0
    return defptr;
891
2.46k
  t = find_sdp_line_delimiter(p + 2, plimit, delimiter);
892
2.46k
  return t ? t : defptr;
893
2.46k
}