Coverage Report

Created: 2025-07-11 06:28

/src/opensips/parser/sdp/sdp.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * SDP parser interface
3
 *
4
 * Copyright (C) 2008 SOMA Networks, INC.
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
 *
23
 * HISTORY:
24
 * --------
25
 * 2007-09-09 osas: ported and enhanced sdp parsing functions from nathelper module
26
 * 2008-04-22 osas: integrated RFC4975 attributes - patch provided by Denis Bilenko (denik)
27
 *
28
 */
29
30
31
#include "../../ut.h"
32
#include "../../trim.h"
33
#include "../../mem/mem.h"
34
#include "../../mem/shm_mem.h"
35
#include "../parser_f.h"
36
#include "../parse_content.h"
37
#include "../parse_body.h"
38
#include "sdp.h"
39
#include "sdp_helpr_funcs.h"
40
41
0
#define USE_PKG_MEM 0
42
0
#define USE_SHM_MEM 1
43
44
0
#define HOLD_IP_STR "0.0.0.0"
45
0
#define HOLD_IP_LEN 7
46
47
/**
48
 * Alocate a new session cell.
49
 */
50
static inline sdp_session_cell_t *add_sdp_session(sdp_info_t* _sdp, int session_num, str* cnt_disp, str body)
51
0
{
52
0
  sdp_session_cell_t *session;
53
0
  int len;
54
55
0
  len = sizeof(sdp_session_cell_t);
56
0
  session = (sdp_session_cell_t*)pkg_malloc(len);
57
0
  if (session == NULL) {
58
0
    LM_ERR("No memory left\n");
59
0
    return NULL;
60
0
  }
61
0
  memset( session, 0, len);
62
63
0
  session->session_num = session_num;
64
0
  if (cnt_disp != NULL) {
65
0
    session->cnt_disp.s = cnt_disp->s;
66
0
    session->cnt_disp.len = cnt_disp->len;
67
0
  }
68
69
0
  session->body = body;
70
71
  /* Insert the new session */
72
0
  session->next = _sdp->sessions;
73
0
  _sdp->sessions = session;
74
0
  _sdp->sessions_num++;
75
76
0
  return session;
77
0
}
78
79
/**
80
 * Allocate a new stream cell.
81
 */
82
static inline sdp_stream_cell_t *add_sdp_stream(sdp_session_cell_t* _session, int stream_num,
83
    str* media, str* port, str* transport, str* payloads, int is_rtp, int pf, str* sdp_ip, str body)
84
0
{
85
0
  sdp_stream_cell_t *stream;
86
0
  int len;
87
88
0
  len = sizeof(sdp_stream_cell_t);
89
0
  stream = (sdp_stream_cell_t*)pkg_malloc(len);
90
0
  if (stream == NULL) {
91
0
    LM_ERR("No memory left\n");
92
0
    return NULL;
93
0
  }
94
0
  memset( stream, 0, len);
95
96
0
  stream->stream_num = stream_num;
97
98
0
  stream->media.s = media->s;
99
0
  stream->media.len = media->len;
100
0
  stream->port.s = port->s;
101
0
  stream->port.len = port->len;
102
0
  stream->transport.s = transport->s;
103
0
  stream->transport.len = transport->len;
104
0
  stream->payloads.s = payloads->s;
105
0
  stream->payloads.len = payloads->len;
106
107
0
  stream->is_rtp = is_rtp;
108
109
0
  stream->pf = pf;
110
0
  stream->ip_addr.s = sdp_ip->s;
111
0
  stream->ip_addr.len = sdp_ip->len;
112
113
0
  stream->body = body;
114
115
  /* Insert the new stream */
116
0
  stream->next = _session->streams;
117
0
  _session->streams = stream;
118
0
  _session->streams_num++;
119
120
0
  return stream;
121
0
}
122
123
/**
124
 * Allocate a new payload.
125
 */
126
static inline sdp_payload_attr_t *add_sdp_payload(sdp_stream_cell_t* _stream, int payload_num, str* payload)
127
0
{
128
0
  sdp_payload_attr_t *payload_attr;
129
0
  int len;
130
131
0
  len = sizeof(sdp_payload_attr_t);
132
0
  payload_attr = (sdp_payload_attr_t*)pkg_malloc(len);
133
0
  if (payload_attr == NULL) {
134
0
    LM_ERR("No memory left\n");
135
0
    return NULL;
136
0
  }
137
0
  memset( payload_attr, 0, len);
138
139
0
  payload_attr->payload_num = payload_num;
140
0
  payload_attr->rtp_payload.s = payload->s;
141
0
  payload_attr->rtp_payload.len = payload->len;
142
143
  /* Insert the new payload */
144
0
  payload_attr->next = _stream->payload_attr;
145
0
  _stream->payload_attr = payload_attr;
146
0
  _stream->payloads_num++;
147
148
0
  return payload_attr;
149
0
}
150
151
/**
152
 * Initialize fast access pointers.
153
 */
154
static inline sdp_payload_attr_t** init_p_payload_attr(sdp_stream_cell_t* _stream, int pkg)
155
0
{
156
0
  int payloads_num, i;
157
0
  sdp_payload_attr_t *payload;
158
159
0
  if (_stream == NULL) {
160
0
    LM_ERR("Invalid stream\n");
161
0
    return NULL;
162
0
  }
163
0
  payloads_num = _stream->payloads_num;
164
0
  if (payloads_num == 0) {
165
0
    LM_ERR("Invalid number of payloads\n");
166
0
    return NULL;
167
0
  }
168
0
  if (pkg == USE_PKG_MEM) {
169
0
    _stream->p_payload_attr = (sdp_payload_attr_t**)pkg_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
170
0
  } else if (pkg == USE_SHM_MEM) {
171
0
    _stream->p_payload_attr = (sdp_payload_attr_t**)shm_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
172
0
  } else {
173
0
    LM_ERR("undefined memory type\n");
174
0
    return NULL;
175
0
  }
176
0
  if (_stream->p_payload_attr == NULL) {
177
0
    LM_ERR("No memory left\n");
178
0
    return NULL;
179
0
  }
180
181
0
  --payloads_num;
182
0
  payload = _stream->payload_attr;
183
0
  for (i=0;i<=payloads_num;i++) {
184
0
    _stream->p_payload_attr[payloads_num-i] = payload;
185
0
    payload = payload->next;
186
0
  }
187
188
0
  return _stream->p_payload_attr;
189
0
}
190
191
/*
192
 * Setters ...
193
 */
194
195
void set_sdp_payload_attr(sdp_payload_attr_t *payload_attr, str *rtp_enc, str *rtp_clock, str *rtp_params)
196
0
{
197
0
  payload_attr->rtp_enc.s = rtp_enc->s;
198
0
  payload_attr->rtp_enc.len = rtp_enc->len;
199
0
  payload_attr->rtp_clock.s = rtp_clock->s;
200
0
  payload_attr->rtp_clock.len = rtp_clock->len;
201
0
  payload_attr->rtp_params.s = rtp_params->s;
202
0
  payload_attr->rtp_params.len = rtp_params->len;
203
204
0
  return;
205
0
}
206
207
void set_sdp_payload_fmtp(sdp_payload_attr_t *payload_attr, str *fmtp_string )
208
0
{
209
0
  if (payload_attr == NULL) {
210
0
    LM_ERR("Invalid payload location\n");
211
0
    return;
212
0
  }
213
214
0
  payload_attr->fmtp_string.s = fmtp_string->s;
215
0
  payload_attr->fmtp_string.len = fmtp_string->len;
216
217
0
  return;
218
0
}
219
220
void try_set_fmtp_payload_link(sdp_stream_cell_t *stream,sdp_payload_attr_t *payload_attr, str *fmtp_string )
221
0
{
222
0
  str link_str=str_init("apt=");
223
0
  char *p_start,*p_end;
224
0
  str ref_payload_s;
225
0
  sdp_payload_attr_t *ref_payload;
226
227
0
  if (payload_attr == NULL) {
228
0
    LM_ERR("Invalid payload location\n");
229
0
    return;
230
0
  }
231
232
  /* apt=xxx */
233
0
  if (fmtp_string->len < 4) {
234
0
    LM_DBG("Too small body \n");
235
0
    return;
236
0
  }
237
238
0
  LM_DBG("We need to link [%.*s] to [%.*s]\n",fmtp_string->len,fmtp_string->s,payload_attr->rtp_payload.len,payload_attr->rtp_payload.s);
239
240
0
  if ((p_start = str_strstr(fmtp_string,&link_str)) == NULL) {
241
0
    return;
242
0
  }
243
244
  /* skip it */
245
0
  p_start += link_str.len; 
246
0
  ref_payload_s.s = p_start;
247
0
  for (p_end=p_start;p_end<fmtp_string->s+fmtp_string->len;p_end++) {
248
0
    if (*p_end==';')
249
0
      break;
250
0
  }
251
252
0
  ref_payload_s.len = p_end-p_start;
253
0
  trim(&ref_payload_s);
254
255
0
  ref_payload = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &ref_payload_s);
256
0
  if (ref_payload == NULL)
257
0
    return;
258
259
0
  LM_DBG("Found it, %.*s going to %.*s\n",ref_payload_s.len,ref_payload_s.s,ref_payload->rtp_payload.len,ref_payload->rtp_payload.s);
260
261
0
  ref_payload->linked_payload = payload_attr; 
262
0
  return;
263
0
}
264
265
void set_sdp_payload_custom_attr(sdp_payload_attr_t *payload_attr, str *attr )
266
0
{
267
0
  if (payload_attr == NULL) {
268
0
    LM_DBG("No payload_attr\n");
269
0
    return;
270
0
  }
271
0
  if (payload_attr->custom_attrs_size == MAX_CUSTOM_ATTRS-1) {
272
0
    LM_DBG("Max custom a= attrs reached \n");
273
0
    return;
274
0
  }
275
276
0
  payload_attr->custom_attrs[payload_attr->custom_attrs_size++] = *attr;
277
0
  return;
278
0
}
279
280
/*
281
 * Getters ....
282
 */
283
sdp_session_cell_t* get_sdp_session(sdp_info_t* sdp, int session_num)
284
0
{
285
0
  sdp_session_cell_t *session;
286
287
0
  session = sdp->sessions;
288
0
  if (session_num >= sdp->sessions_num) return NULL;
289
0
  while (session) {
290
0
    if (session->session_num == session_num) return session;
291
0
    session = session->next;
292
0
  }
293
0
  return NULL;
294
0
}
295
296
sdp_stream_cell_t* get_sdp_stream(sdp_info_t* sdp, int session_num,
297
                                int stream_num)
298
0
{
299
0
  sdp_session_cell_t *session;
300
0
  sdp_stream_cell_t *stream;
301
302
0
  if (sdp==NULL) return NULL;
303
0
  if (session_num >= sdp->sessions_num) return NULL;
304
0
  session = sdp->sessions;
305
0
  while (session) {
306
0
    if (session->session_num == session_num) {
307
0
      if (stream_num >= session->streams_num) return NULL;
308
0
      stream = session->streams;
309
0
      while (stream) {
310
0
        if (stream->stream_num == stream_num) return stream;
311
0
        stream = stream->next;
312
0
      }
313
0
      break;
314
0
    } else {
315
0
      session = session->next;
316
0
    }
317
0
  }
318
319
0
  return NULL;
320
0
}
321
322
sdp_payload_attr_t* get_sdp_payload4payload(sdp_stream_cell_t *stream, str *rtp_payload)
323
0
{
324
0
  sdp_payload_attr_t *payload;
325
0
  int i;
326
327
0
  if (stream == NULL) {
328
0
    LM_ERR("Invalid stream location\n");
329
0
    return NULL;
330
0
  }
331
0
  if (stream->p_payload_attr == NULL) {
332
0
    LM_ERR("Invalid access pointer to payloads\n");
333
0
    return NULL;
334
0
  }
335
336
0
  for (i=0;i<stream->payloads_num;i++) {
337
0
    payload = stream->p_payload_attr[i];
338
0
    if (rtp_payload->len == payload->rtp_payload.len &&
339
0
      (strncmp(rtp_payload->s, payload->rtp_payload.s, rtp_payload->len)==0)) {
340
0
      return payload;
341
0
    }
342
0
  }
343
344
0
  return NULL;
345
0
}
346
347
sdp_payload_attr_t* get_sdp_payload4index(sdp_stream_cell_t *stream, int index)
348
0
{
349
0
  if (stream == NULL) {
350
0
    LM_ERR("Invalid stream location\n");
351
0
    return NULL;
352
0
  }
353
0
  if (stream->p_payload_attr == NULL) {
354
0
    LM_ERR("Invalid access pointer to payloads\n");
355
0
    return NULL;
356
0
  }
357
0
  if (index >= stream->payloads_num) {
358
0
    LM_ERR("Out of range index [%d] for payload\n", index);
359
0
    return NULL;
360
0
  }
361
362
0
  return stream->p_payload_attr[index];
363
0
}
364
365
/**
366
 * Add SDP attribute.
367
 */
368
static inline int add_sdp_attr(str line, sdp_attr_t **list)
369
0
{
370
0
  char *p;
371
0
  static sdp_attr_t *last;
372
0
  sdp_attr_t *a = pkg_malloc(sizeof *a);
373
0
  if (!a) {
374
0
    LM_ERR("No memory left!\n");
375
0
    return -1;
376
0
  }
377
0
  memset(a, 0, sizeof *a);
378
379
  /* check for value separator : */
380
0
  p = q_memchr(line.s + 2, ':', line.len - 2);
381
0
  if (p) {
382
0
    a->attribute.s = line.s + 2;
383
0
    a->attribute.len = p - a->attribute.s;
384
    /* skip the separator */
385
0
    a->value.s = p + 1;
386
0
    a->value.len = line.len - (a->value.s - line.s);
387
0
    trim(&a->value);
388
0
  } else {
389
0
    a->attribute.s = line.s + 2;
390
0
    a->attribute.len = line.len - 2;
391
0
  }
392
0
  trim(&a->attribute);
393
394
  /* link it to the list */
395
0
  if (*list)
396
0
    last->next = a;
397
0
  else
398
0
    *list = a;
399
  /* we remember the last object added */
400
0
  last = a;
401
402
0
  return 0;
403
0
}
404
405
/**
406
 * SDP parser method.
407
 */
408
int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_info_t* _sdp)
409
0
{
410
0
  str body = *sdp_body;
411
0
  str sdp_ip = {NULL,0};
412
0
  str sdp_media, sdp_port, sdp_transport, sdp_payload;
413
0
  str payload;
414
0
  str rtp_payload, rtp_enc, rtp_clock, rtp_params;
415
0
  int is_rtp;
416
0
  char *bodylimit;
417
0
  char *v1p, *o1p, *m1p, *m2p, *c1p, *c2p, *a1p, *a2p, *b1p;
418
0
  str tmpstr1,custom_attr;
419
0
  int stream_num, payloadnum, pf;
420
0
  sdp_session_cell_t *session;
421
0
  sdp_stream_cell_t *stream;
422
0
  sdp_payload_attr_t *payload_attr;
423
0
  int parse_payload_attr;
424
0
  str fmtp_string;
425
426
  /*
427
   * Parsing of SDP body.
428
   * Each session starts with v-line and each session may contain a few
429
   * media descriptions (each starts with m-line).
430
   * We have to change ports in m-lines, and also change IP addresses in
431
   * c-lines which can be placed either in session header (fallback for
432
   * all medias) or media description.
433
   * Ports should be allocated for any media. IPs all should be changed
434
   * to the same value (RTP proxy IP), so we can change all c-lines
435
   * unconditionally.
436
   */
437
0
  bodylimit = body.s + body.len;
438
0
  if (body.len < 2) {
439
0
    LM_ERR("body too short!\n");
440
0
    return -1;
441
0
  }
442
0
  v1p = body.s;
443
  /* skip over the first initial \r\n  (optional) */
444
0
  if (*v1p == '\r' || *v1p == '\n')
445
0
    v1p++;
446
0
  if (*v1p == '\r' || *v1p == '\n')
447
0
    v1p++;
448
0
  if (v1p + 1 >= bodylimit) {
449
0
    LM_ERR("body too short %ld!\n", (long)(bodylimit - v1p));
450
0
    return -1;
451
0
  }
452
0
  if (*v1p != 'v' || *(v1p+1) != '=') {
453
0
    LM_ERR("invalid SDP start: [%c%c]\n", *v1p, *(v1p + 1));
454
0
    return -1;
455
0
  }
456
  /* get session origin */
457
0
  o1p = find_sdp_line(v1p, bodylimit, 'o');
458
0
  if (o1p == NULL) {
459
0
    LM_ERR("no o= in session\n");
460
0
    return -1;
461
0
  }
462
  /* Have this session media description? */
463
0
  m1p = find_sdp_line(o1p, bodylimit, 'm');
464
0
  if (m1p == NULL) {
465
0
    LM_ERR("no m= in session\n");
466
0
    return -1;
467
0
  }
468
  /* Allocate a session cell */
469
0
  session = add_sdp_session(_sdp, session_num, cnt_disp, body);
470
0
  if (session == NULL) return -1;
471
472
  /* Get origin IP */
473
0
  tmpstr1.s = o1p;
474
0
  tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
475
0
  if (extract_mediaip(&tmpstr1, &session->o_ip_addr, &session->o_pf,"o=") == -1) {
476
0
    LM_ERR("can't extract origin media IP from the message\n");
477
0
    return -1;
478
0
  }
479
480
  /* Find c1p only between session begin and first media.
481
   * c1p will give common c= for all medias. */
482
0
  c1p = find_sdp_line(o1p, m1p, 'c');
483
484
0
  if (c1p) {
485
    /* Extract session address */
486
0
    tmpstr1.s = c1p;
487
0
    tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
488
0
    if (extract_mediaip(&tmpstr1, &session->ip_addr, &session->pf,"c=") == -1) {
489
0
      LM_ERR("can't extract common media IP from the message\n");
490
0
      return -1;
491
0
    }
492
0
  }
493
494
  /* Find b1p only between session begin and first media.
495
   * b1p will give common b= for all medias. */
496
0
  b1p = find_sdp_line(o1p, m1p, 'b');
497
0
  if (b1p) {
498
0
    tmpstr1.s = b1p;
499
0
    tmpstr1.len = m1p - b1p;
500
0
    extract_bwidth(&tmpstr1, &session->bw_type, &session->bw_width);
501
0
  }
502
503
  /* from b1p or o1p down to m1p we have session a= attributes */
504
0
  a1p = find_sdp_line((b1p?b1p:o1p), m1p, 'a');
505
0
  a2p = a1p;
506
0
  for (;;) {
507
0
    a1p = a2p;
508
0
    if (a1p == NULL || a1p >= m1p)
509
0
      break;
510
0
    a2p = find_next_sdp_line(a1p + 1, m1p, 'a', m1p);
511
512
0
    tmpstr1.s = a1p;
513
0
    tmpstr1.len = a2p - a1p;
514
515
0
    if (add_sdp_attr(tmpstr1, &session->attr) < 0)
516
0
      return -1;
517
0
  }
518
519
  /* Have session. Iterate media descriptions in session */
520
0
  m2p = m1p;
521
0
  stream_num = 0;
522
0
  for (;;) {
523
0
    m1p = m2p;
524
0
    if (m1p == NULL || m1p >= bodylimit)
525
0
      break;
526
0
    m2p = find_next_sdp_line(m1p, bodylimit, 'm', bodylimit);
527
    /* c2p will point to per-media "c=" */
528
0
    c2p = find_sdp_line(m1p, m2p, 'c');
529
530
0
    if (c2p) {
531
      /* Extract stream address */
532
0
      tmpstr1.s = c2p;
533
0
      tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
534
0
      if (extract_mediaip(&tmpstr1, &sdp_ip, &pf,"c=") == -1) {
535
0
        LM_ERR("can't extract media IP from the message\n");
536
0
        return -1;
537
0
      }
538
0
    } else {
539
0
      if (!c1p) {
540
        /* No "c=" */
541
0
        LM_ERR("can't find media IP in the message\n");
542
0
        return -1;
543
0
      }
544
      /* take the family from the more specific line */
545
0
      pf = session->pf;
546
0
    }
547
548
    /* Extract the port on sdp_port */
549
0
    tmpstr1.s = m1p;
550
0
    tmpstr1.len = m2p - m1p;
551
0
    if (extract_media_attr(&tmpstr1, &sdp_media, &sdp_port, &sdp_transport, &sdp_payload, &is_rtp) == -1) {
552
0
      LM_ERR("can't extract media attr from the message\n");
553
0
      return -1;
554
0
    }
555
556
    /* Allocate a stream cell */
557
0
    stream = add_sdp_stream(session, stream_num, &sdp_media, &sdp_port, &sdp_transport, &sdp_payload, is_rtp, pf, &sdp_ip, tmpstr1);
558
0
    if (stream == 0) return -1;
559
560
    /* increment total number of streams */
561
0
    _sdp->streams_num++;
562
563
    /* b1p will point to per-media "b=" */
564
0
    b1p = find_sdp_line(m1p, m2p, 'b');
565
0
    if (b1p) {
566
0
      tmpstr1.s = b1p;
567
0
      tmpstr1.len = m2p - b1p;
568
0
      extract_bwidth(&tmpstr1, &stream->bw_type, &stream->bw_width);
569
0
    }
570
571
    /* Parsing the payloads */
572
0
    tmpstr1.s = sdp_payload.s;
573
0
    tmpstr1.len = sdp_payload.len;
574
0
    payloadnum = 0;
575
0
    if (tmpstr1.len != 0) {
576
0
      for (;;) {
577
0
        a1p = eat_token_end(tmpstr1.s, tmpstr1.s + tmpstr1.len);
578
0
        payload.s = tmpstr1.s;
579
0
        payload.len = a1p - tmpstr1.s;
580
0
        payload_attr = add_sdp_payload(stream, payloadnum, &payload);
581
0
        if (payload_attr == NULL) return -1;
582
0
        tmpstr1.len -= payload.len;
583
0
        tmpstr1.s = a1p;
584
0
        a2p = eat_space_end(tmpstr1.s, tmpstr1.s + tmpstr1.len);
585
0
        tmpstr1.len -= a2p - a1p;
586
0
        tmpstr1.s = a2p;
587
0
        if (a1p >= tmpstr1.s)
588
0
          break;
589
0
        payloadnum++;
590
0
      }
591
592
      /* Initialize fast access pointers */
593
0
      if (NULL == init_p_payload_attr(stream, USE_PKG_MEM)) {
594
0
        return -1;
595
0
      }
596
0
      parse_payload_attr = 1;
597
0
    } else {
598
0
      parse_payload_attr = 0;
599
0
    }
600
601
0
    payload_attr = 0;
602
    /* Let's figure out the atributes */
603
0
    a1p = find_sdp_line(m1p, m2p, 'a');
604
0
    a2p = a1p;
605
0
    for (;;) {
606
0
      a1p = a2p;
607
0
      if (a1p == NULL || a1p >= m2p)
608
0
        break;
609
0
      tmpstr1.s = a2p;
610
0
      tmpstr1.len = m2p - a2p;
611
612
0
      if (parse_payload_attr && extract_ptime(&tmpstr1, &stream->ptime) == 0) {
613
0
        a1p = stream->ptime.s + stream->ptime.len;
614
0
      } else if (parse_payload_attr && extract_sendrecv_mode(&tmpstr1,
615
0
          &stream->sendrecv_mode, &stream->is_on_hold) == 0) {
616
0
        a1p = stream->sendrecv_mode.s + stream->sendrecv_mode.len;
617
0
      } else if (parse_payload_attr && extract_rtpmap(&tmpstr1, &rtp_payload, &rtp_enc, &rtp_clock, &rtp_params) == 0) {
618
0
        if (rtp_params.len != 0 && rtp_params.s != NULL) {
619
0
          a1p = rtp_params.s + rtp_params.len;
620
0
        } else {
621
0
          a1p = rtp_clock.s + rtp_clock.len;
622
0
        }
623
0
        payload_attr = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &rtp_payload);
624
0
        if (payload_attr)
625
0
          set_sdp_payload_attr(payload_attr, &rtp_enc, &rtp_clock, &rtp_params);
626
0
      } else if (extract_rtcp(&tmpstr1, &stream->rtcp_port) == 0) {
627
0
        a1p = stream->rtcp_port.s + stream->rtcp_port.len;
628
0
      } else if (parse_payload_attr && extract_fmtp(&tmpstr1,&rtp_payload,&fmtp_string) == 0){
629
0
        LM_DBG("Found FMTP [%.*s] for payload [%.*s]\n",fmtp_string.len,fmtp_string.s,rtp_payload.len,rtp_payload.s);
630
0
        a1p = fmtp_string.s + fmtp_string.len;
631
0
        payload_attr = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &rtp_payload);
632
0
        set_sdp_payload_fmtp(payload_attr, &fmtp_string);
633
634
0
        try_set_fmtp_payload_link(stream,payload_attr,&fmtp_string);
635
0
      } else if (extract_accept_types(&tmpstr1, &stream->accept_types) == 0) {
636
0
        a1p = stream->accept_types.s + stream->accept_types.len;
637
0
      } else if (extract_accept_wrapped_types(&tmpstr1, &stream->accept_wrapped_types) == 0) {
638
0
        a1p = stream->accept_wrapped_types.s + stream->accept_wrapped_types.len;
639
0
      } else if (extract_max_size(&tmpstr1, &stream->max_size) == 0) {
640
0
        a1p = stream->max_size.s + stream->max_size.len;
641
0
      } else if (extract_path(&tmpstr1, &stream->path) == 0) {
642
0
        a1p = stream->path.s + stream->path.len;
643
0
      } else {
644
0
        if (parse_payload_attr && extract_custom_a_attr(&tmpstr1,&rtp_payload,&custom_attr) == 0) {
645
0
          LM_DBG("extracted attr [%.*s] for payload [%.*s]\n",custom_attr.len,custom_attr.s,rtp_payload.len,rtp_payload.s);
646
0
          a1p = custom_attr.s + custom_attr.len;
647
0
          payload_attr = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &rtp_payload);
648
0
          set_sdp_payload_custom_attr(payload_attr, &custom_attr);
649
0
        } else {
650
0
          LM_DBG("else: parse_payload_attr ? %d `%.*s'\n",parse_payload_attr, tmpstr1.len, tmpstr1.s);
651
0
        }
652
0
      }
653
654
0
      tmpstr1.s = a2p;
655
0
      a2p = find_next_sdp_line(a1p-1, m2p, 'a', m2p);
656
0
      tmpstr1.len = a2p - tmpstr1.s;
657
658
0
      if (add_sdp_attr(tmpstr1, &stream->attr) < 0)
659
0
        return -1;
660
0
    }
661
    /* Let's detect if the media is on hold by checking
662
     * the good old "0.0.0.0" connection address */
663
0
    if (!stream->is_on_hold) {
664
0
      if (stream->ip_addr.s && stream->ip_addr.len) {
665
0
        if (stream->ip_addr.len == HOLD_IP_LEN &&
666
0
          strncmp(stream->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
667
0
          stream->is_on_hold = RFC2543_HOLD;
668
0
      } else if (session->ip_addr.s && session->ip_addr.len) {
669
0
        if (session->ip_addr.len == HOLD_IP_LEN &&
670
0
          strncmp(session->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
671
0
          stream->is_on_hold = RFC2543_HOLD;
672
0
      }
673
0
    }
674
0
    ++stream_num;
675
0
  } /* Iterate medias/streams in session */
676
0
  return 0;
677
0
}
678
679
680
/**
681
 * Parse all SDP parts from the SIP body.
682
 *
683
 * returns the first found SDP on success
684
 * returns NULL if no SDP found or if error
685
 */
686
sdp_info_t* parse_sdp(struct sip_msg* _m)
687
0
{
688
0
  struct body_part *part;
689
0
  sdp_info_t *sdp, *ret;
690
691
0
  if ( parse_sip_body(_m)<0 || _m->body==NULL) {
692
0
    LM_DBG("message body has length zero: %p\n", _m->body);
693
0
    return NULL;
694
0
  }
695
696
0
  ret = NULL;
697
698
  /* iterate all body parts and look for the SDP mime */
699
0
  for( part=&_m->body->first ; part ; part=part->next) {
700
701
    /* skip body parts which were deleted or newly added */
702
0
    if (!is_body_part_received(part))
703
0
      continue;
704
705
0
    if ( part->mime != ((TYPE_APPLICATION<<16)+SUBTYPE_SDP) )
706
0
      continue;
707
708
0
    if (part->parsed) {
709
0
      if (!ret)
710
0
        ret = part->parsed;
711
0
      continue;
712
0
    }
713
714
0
    if ( (sdp=new_sdp())==NULL ) {
715
0
      LM_ERR("Can't create new sdp, skipping\n");
716
0
    } else {
717
0
      if (parse_sdp_session(&part->body, 0, NULL, sdp)<0) {
718
0
        LM_ERR("failed to parse SDP for body part, skipping\n");
719
0
        free_sdp( sdp );
720
0
      } else {
721
0
        part->parsed = (void*)sdp;
722
0
        part->free_parsed_f = (free_parsed_part_function)free_sdp;
723
        /* remember the first found SDP */
724
0
        if (!ret) ret = sdp;
725
0
      }
726
0
    }
727
0
  }
728
729
0
  return ret;
730
0
}
731
732
void free_sdp_content(sdp_info_t* sdp)
733
0
{
734
0
  sdp_session_cell_t *session, *l_session;
735
0
  sdp_stream_cell_t *stream, *l_stream;
736
0
  sdp_payload_attr_t *payload, *l_payload;
737
0
  sdp_attr_t *attr, *l_attr;
738
739
0
  LM_DBG("sdp = %p\n", sdp);
740
0
  if (sdp == NULL) return;
741
0
  LM_DBG("sdp = %p\n", sdp);
742
0
  session = sdp->sessions;
743
0
  LM_DBG("session = %p\n", session);
744
0
  while (session) {
745
0
    l_session = session;
746
0
    session = session->next;
747
0
    attr = l_session->attr;
748
0
    while (attr) {
749
0
      l_attr = attr;
750
0
      attr = attr->next;
751
0
      pkg_free(l_attr);
752
0
    }
753
0
    stream = l_session->streams;
754
0
    while (stream) {
755
0
      l_stream = stream;
756
0
      stream = stream->next;
757
0
      payload = l_stream->payload_attr;
758
0
      while (payload) {
759
0
        l_payload = payload;
760
0
        payload = payload->next;
761
0
        pkg_free(l_payload);
762
0
      }
763
0
      attr = l_stream->attr;
764
0
      while (attr) {
765
0
        l_attr = attr;
766
0
        attr = attr->next;
767
0
        pkg_free(l_attr);
768
0
      }
769
0
      if (l_stream->p_payload_attr) {
770
0
        pkg_free(l_stream->p_payload_attr);
771
0
      }
772
0
      pkg_free(l_stream);
773
0
    }
774
0
    pkg_free(l_session);
775
0
  }
776
0
}
777
778
void print_sdp_stream(sdp_stream_cell_t *stream, int level)
779
0
{
780
0
  sdp_payload_attr_t *payload;
781
782
0
  LM_GEN1(level, "....stream[%d]:%p=>%p {%p} '%.*s' '%.*s:%.*s:%.*s' '%.*s' [%d] '%.*s' '%.*s:%.*s' (%d)=>%p '%.*s' '%.*s' '%.*s' '%.*s' '%.*s' '%.*s'\n",
783
0
    stream->stream_num, stream, stream->next,
784
0
    stream->p_payload_attr,
785
0
    stream->media.len, stream->media.s,
786
0
    stream->ip_addr.len, stream->ip_addr.s, stream->port.len, stream->port.s,
787
0
    stream->rtcp_port.len, stream->rtcp_port.s,
788
0
    stream->transport.len, stream->transport.s, stream->is_rtp,
789
0
    stream->payloads.len, stream->payloads.s,
790
0
    stream->bw_type.len, stream->bw_type.s, stream->bw_width.len, stream->bw_width.s,
791
0
    stream->payloads_num, stream->payload_attr,
792
0
    stream->sendrecv_mode.len, stream->sendrecv_mode.s,
793
0
    stream->ptime.len, stream->ptime.s,
794
0
    stream->path.len, stream->path.s,
795
0
    stream->max_size.len, stream->max_size.s,
796
0
    stream->accept_types.len, stream->accept_types.s,
797
0
    stream->accept_wrapped_types.len, stream->accept_wrapped_types.s);
798
0
  payload = stream->payload_attr;
799
0
  while (payload) {
800
0
    LM_GEN1(level, "......payload[%d]:%p=>%p p_payload_attr[%d]:%p '%.*s' '%.*s' '%.*s' '%.*s' '%.*s'\n",
801
0
      payload->payload_num, payload, payload->next,
802
0
      payload->payload_num, stream->p_payload_attr[payload->payload_num],
803
0
      payload->rtp_payload.len, payload->rtp_payload.s,
804
0
      payload->rtp_enc.len, payload->rtp_enc.s,
805
0
      payload->rtp_clock.len, payload->rtp_clock.s,
806
0
      payload->rtp_params.len, payload->rtp_params.s,
807
0
      payload->fmtp_string.len, payload->fmtp_string.s);
808
0
    payload=payload->next;
809
0
  }
810
0
}
811
812
void print_sdp_session(sdp_session_cell_t *session, int level)
813
0
{
814
0
  sdp_stream_cell_t *stream = session==NULL ? NULL : session->streams;
815
816
0
  if (session==NULL) {
817
0
    LM_ERR("NULL session\n");
818
0
    return;
819
0
  }
820
821
0
  LM_GEN1(level, "..session[%d]:%p=>%p '%.*s' '%.*s' '%.*s' '%.*s:%.*s' (%d)=>%p\n",
822
0
    session->session_num, session, session->next,
823
0
    session->cnt_disp.len, session->cnt_disp.s,
824
0
    session->ip_addr.len, session->ip_addr.s,
825
0
    session->o_ip_addr.len, session->o_ip_addr.s,
826
0
    session->bw_type.len, session->bw_type.s, session->bw_width.len, session->bw_width.s,
827
0
    session->streams_num, session->streams);
828
0
  while (stream) {
829
0
    print_sdp_stream(stream, level);
830
0
    stream=stream->next;
831
0
  }
832
0
}
833
834
835
void print_sdp(sdp_info_t* sdp, int level)
836
0
{
837
0
  sdp_session_cell_t *session;
838
839
0
  LM_GEN1(level, "sdp:%p=>%p (%d:%d)\n", sdp, sdp->sessions, sdp->sessions_num, sdp->streams_num);
840
0
  session = sdp->sessions;
841
0
  while (session) {
842
0
    print_sdp_session(session, level);
843
0
    session = session->next;
844
0
  }
845
0
}
846
847
/*
848
 * Free cloned stream.
849
 */
850
void free_cloned_sdp_stream(sdp_stream_cell_t *_stream)
851
0
{
852
0
  sdp_stream_cell_t *stream, *l_stream;
853
0
  sdp_payload_attr_t *payload, *l_payload;
854
855
0
  stream = _stream;
856
0
  while (stream) {
857
0
    l_stream = stream;
858
0
    stream = stream->next;
859
0
    payload = l_stream->payload_attr;
860
0
    while (payload) {
861
0
      l_payload = payload;
862
0
      payload = payload->next;
863
0
      shm_free(l_payload);
864
0
    }
865
0
    if (l_stream->p_payload_attr) {
866
0
      shm_free(l_stream->p_payload_attr);
867
0
    }
868
0
    shm_free(l_stream);
869
0
  }
870
0
}
871
872
/*
873
 * Free cloned session.
874
 */
875
void free_cloned_sdp_session(sdp_session_cell_t *_session)
876
0
{
877
0
  sdp_session_cell_t *session, *l_session;
878
879
0
  session = _session;
880
0
  while (session) {
881
0
    l_session = session;
882
0
    session = l_session->next;
883
0
    free_cloned_sdp_stream(l_session->streams);
884
0
    shm_free(l_session);
885
0
  }
886
0
}
887
888
void free_cloned_sdp(sdp_info_t* sdp)
889
0
{
890
0
  free_cloned_sdp_session(sdp->sessions);
891
0
  shm_free(sdp);
892
0
}
893
894
sdp_payload_attr_t * clone_sdp_payload_attr(sdp_payload_attr_t *attr)
895
0
{
896
0
  sdp_payload_attr_t * clone_attr;
897
0
  int len;
898
0
  char *p;
899
900
0
  if (attr == NULL) {
901
0
    LM_ERR("arg:NULL\n");
902
0
    return NULL;
903
0
  }
904
905
0
  len = sizeof(sdp_payload_attr_t) +
906
0
      attr->rtp_payload.len +
907
0
      attr->rtp_enc.len +
908
0
      attr->rtp_clock.len +
909
0
      attr->rtp_params.len +
910
0
      attr->fmtp_string.len;
911
0
  clone_attr = (sdp_payload_attr_t*)shm_malloc(len);
912
0
  if (clone_attr == NULL) {
913
0
    LM_ERR("no more shm mem (%d)\n",len);
914
0
    return NULL;
915
0
  }
916
0
  memset( clone_attr, 0, len);
917
0
  p = (char*)(clone_attr+1);
918
919
0
  clone_attr->payload_num = attr->payload_num;
920
921
0
  if (attr->rtp_payload.len) {
922
0
    clone_attr->rtp_payload.s = p;
923
0
    clone_attr->rtp_payload.len = attr->rtp_payload.len;
924
0
    memcpy( p, attr->rtp_payload.s, attr->rtp_payload.len);
925
0
    p += attr->rtp_payload.len;
926
0
  }
927
928
0
  if (attr->rtp_enc.len) {
929
0
    clone_attr->rtp_enc.s = p;
930
0
    clone_attr->rtp_enc.len = attr->rtp_enc.len;
931
0
    memcpy( p, attr->rtp_enc.s, attr->rtp_enc.len);
932
0
    p += attr->rtp_enc.len;
933
0
  }
934
935
0
  if (attr->rtp_clock.len) {
936
0
    clone_attr->rtp_clock.s = p;
937
0
    clone_attr->rtp_clock.len = attr->rtp_clock.len;
938
0
    memcpy( p, attr->rtp_clock.s, attr->rtp_clock.len);
939
0
    p += attr->rtp_clock.len;
940
0
  }
941
942
0
  if (attr->rtp_params.len) {
943
0
    clone_attr->rtp_params.s = p;
944
0
    clone_attr->rtp_params.len = attr->rtp_params.len;
945
0
    memcpy( p, attr->rtp_params.s, attr->rtp_params.len);
946
0
    p += attr->rtp_params.len;
947
0
  }
948
949
0
  if (attr->fmtp_string.len) {
950
0
    clone_attr->fmtp_string.s = p;
951
0
    clone_attr->fmtp_string.len = attr->fmtp_string.len;
952
0
    memcpy( p, attr->fmtp_string.s, attr->fmtp_string.len);
953
0
    p += attr->fmtp_string.len;
954
0
  }
955
956
0
  return clone_attr;
957
0
}
958
959
sdp_stream_cell_t * clone_sdp_stream_cell(sdp_stream_cell_t *stream)
960
0
{
961
0
  sdp_stream_cell_t *clone_stream;
962
0
  sdp_payload_attr_t *clone_payload_attr, *payload_attr;
963
0
  int len, i;
964
0
  char *p;
965
966
0
  if (stream == NULL) {
967
0
    LM_ERR("arg:NULL\n");
968
0
    return NULL;
969
0
  }
970
971
  /* NOTE: we are not cloning RFC4975 attributes */
972
0
  len = sizeof(sdp_stream_cell_t) +
973
0
      stream->ip_addr.len +
974
0
      stream->media.len +
975
0
      stream->port.len +
976
0
      stream->transport.len +
977
0
      stream->sendrecv_mode.len +
978
0
      stream->ptime.len +
979
0
      stream->payloads.len +
980
0
      stream->bw_type.len +
981
0
      stream->bw_width.len +
982
0
      stream->rtcp_port.len;
983
0
  clone_stream = (sdp_stream_cell_t*)shm_malloc(len);
984
0
  if (clone_stream == NULL) {
985
0
    LM_ERR("no more shm mem (%d)\n",len);
986
0
    return NULL;
987
0
  }
988
0
  memset( clone_stream, 0, len);
989
0
  p = (char*)(clone_stream+1);
990
991
0
  payload_attr = NULL;
992
0
  for (i=0;i<stream->payloads_num;i++) {
993
0
    clone_payload_attr = clone_sdp_payload_attr(stream->p_payload_attr[i]);
994
0
    if (clone_payload_attr == NULL) {
995
0
      LM_ERR("unable to clone attributes for payload[%d]\n", i);
996
0
      goto error;
997
0
    }
998
0
    clone_payload_attr->next = payload_attr;
999
0
    payload_attr = clone_payload_attr;
1000
0
  }
1001
0
  clone_stream->payload_attr = payload_attr;
1002
1003
0
  clone_stream->payloads_num = stream->payloads_num;
1004
0
  if (clone_stream->payloads_num) {
1005
0
    if (NULL == init_p_payload_attr(clone_stream, USE_SHM_MEM)) {
1006
0
      goto error;
1007
0
    }
1008
0
  }
1009
1010
0
  clone_stream->stream_num = stream->stream_num;
1011
0
  clone_stream->pf = stream->pf;
1012
1013
0
  if (stream->ip_addr.len) {
1014
0
    clone_stream->ip_addr.s = p;
1015
0
    clone_stream->ip_addr.len = stream->ip_addr.len;
1016
0
    memcpy( p, stream->ip_addr.s, stream->ip_addr.len);
1017
0
    p += stream->ip_addr.len;
1018
0
  }
1019
1020
0
  clone_stream->is_rtp = stream->is_rtp;
1021
1022
0
  if (stream->media.len) {
1023
0
    clone_stream->media.s = p;
1024
0
    clone_stream->media.len = stream->media.len;
1025
0
    memcpy( p, stream->media.s, stream->media.len);
1026
0
    p += stream->media.len;
1027
0
  }
1028
1029
0
  if (stream->port.len) {
1030
0
    clone_stream->port.s = p;
1031
0
    clone_stream->port.len = stream->port.len;
1032
0
    memcpy( p, stream->port.s, stream->port.len);
1033
0
    p += stream->port.len;
1034
0
  }
1035
1036
0
  if (stream->transport.len) {
1037
0
    clone_stream->transport.s = p;
1038
0
    clone_stream->transport.len = stream->transport.len;
1039
0
    memcpy( p, stream->transport.s, stream->transport.len);
1040
0
    p += stream->transport.len;
1041
0
  }
1042
1043
0
  if (stream->sendrecv_mode.len) {
1044
0
    clone_stream->sendrecv_mode.s = p;
1045
0
    clone_stream->sendrecv_mode.len = stream->sendrecv_mode.len;
1046
0
    memcpy( p, stream->sendrecv_mode.s, stream->sendrecv_mode.len);
1047
0
    p += stream->sendrecv_mode.len;
1048
0
  }
1049
1050
0
  if (stream->ptime.len) {
1051
0
    clone_stream->ptime.s = p;
1052
0
    clone_stream->ptime.len = stream->ptime.len;
1053
0
    memcpy( p, stream->ptime.s, stream->ptime.len);
1054
0
    p += stream->ptime.len;
1055
0
  }
1056
1057
0
  if (stream->payloads.len) {
1058
0
    clone_stream->payloads.s = p;
1059
0
    clone_stream->payloads.len = stream->payloads.len;
1060
0
    memcpy( p, stream->payloads.s, stream->payloads.len);
1061
0
    p += stream->payloads.len;
1062
0
  }
1063
1064
0
  if (stream->bw_type.len) {
1065
0
    clone_stream->bw_type.s = p;
1066
0
    clone_stream->bw_type.len = stream->bw_type.len;
1067
0
    p += stream->bw_type.len;
1068
0
  }
1069
1070
0
  if (stream->bw_width.len) {
1071
0
    clone_stream->bw_width.s = p;
1072
0
    clone_stream->bw_width.len = stream->bw_width.len;
1073
0
    p += stream->bw_width.len;
1074
0
  }
1075
1076
0
  if (stream->rtcp_port.len) {
1077
0
    clone_stream->rtcp_port.s = p;
1078
0
    clone_stream->rtcp_port.len = stream->rtcp_port.len;
1079
0
    memcpy( p, stream->rtcp_port.s, stream->rtcp_port.len);
1080
0
    p += stream->rtcp_port.len;
1081
0
  }
1082
1083
  /* NOTE: we are not cloning RFC4975 attributes:
1084
   * - path
1085
   * - max_size
1086
   * - accept_types
1087
   * - accept_wrapped_types
1088
   */
1089
1090
0
  return clone_stream;
1091
0
error:
1092
0
  free_cloned_sdp_stream(clone_stream);
1093
0
  return NULL;
1094
0
}
1095
1096
sdp_session_cell_t * clone_sdp_session_cell(sdp_session_cell_t *session)
1097
0
{
1098
0
  sdp_session_cell_t *clone_session;
1099
0
  sdp_stream_cell_t *clone_stream, *prev_clone_stream, *stream;
1100
0
  int len, i;
1101
0
  char *p;
1102
1103
0
  if (session == NULL) {
1104
0
    LM_ERR("arg:NULL\n");
1105
0
    return NULL;
1106
0
  }
1107
0
  len = sizeof(sdp_session_cell_t) +
1108
0
    session->cnt_disp.len +
1109
0
    session->ip_addr.len +
1110
0
    session->o_ip_addr.len +
1111
0
    session->bw_type.len +
1112
0
    session->bw_width.len;
1113
0
  clone_session = (sdp_session_cell_t*)shm_malloc(len);
1114
0
  if (clone_session == NULL) {
1115
0
    LM_ERR("no more shm mem (%d)\n",len);
1116
0
    return NULL;
1117
0
  }
1118
0
  memset( clone_session, 0, len);
1119
0
  p = (char*)(clone_session+1);
1120
1121
0
  if (session->streams_num) {
1122
0
    stream=session->streams;
1123
0
    clone_stream=clone_sdp_stream_cell(stream);
1124
0
    if (clone_stream==NULL) {
1125
0
      goto error;
1126
0
    }
1127
0
    clone_session->streams=clone_stream;
1128
0
    prev_clone_stream=clone_stream;
1129
0
    stream=stream->next;
1130
0
    for (i=1;i<session->streams_num;i++) {
1131
0
      clone_stream=clone_sdp_stream_cell(stream);
1132
0
      if (clone_stream==NULL) {
1133
0
        goto error;
1134
0
      }
1135
0
      prev_clone_stream->next=clone_stream;
1136
0
      prev_clone_stream=clone_stream;
1137
0
      stream=stream->next;
1138
0
    }
1139
0
  }
1140
1141
0
  clone_session->session_num = session->session_num;
1142
0
  clone_session->pf = session->pf;
1143
0
  clone_session->o_pf = session->o_pf;
1144
0
  clone_session->streams_num = session->streams_num;
1145
1146
0
  if (session->cnt_disp.len) {
1147
0
    clone_session->cnt_disp.s = p;
1148
0
    clone_session->cnt_disp.len = session->cnt_disp.len;
1149
0
    memcpy( p, session->cnt_disp.s, session->cnt_disp.len);
1150
0
    p += session->cnt_disp.len;
1151
0
  }
1152
1153
0
  if (session->ip_addr.len) {
1154
0
    clone_session->ip_addr.s = p;
1155
0
    clone_session->ip_addr.len = session->ip_addr.len;
1156
0
    memcpy( p, session->ip_addr.s, session->ip_addr.len);
1157
0
    p += session->ip_addr.len;
1158
0
  }
1159
1160
0
  if (session->o_ip_addr.len) {
1161
0
    clone_session->o_ip_addr.s = p;
1162
0
    clone_session->o_ip_addr.len = session->o_ip_addr.len;
1163
0
    memcpy( p, session->o_ip_addr.s, session->o_ip_addr.len);
1164
0
    p += session->o_ip_addr.len;
1165
0
  }
1166
1167
0
  if (session->bw_type.len) {
1168
0
    clone_session->bw_type.s = p;
1169
0
    clone_session->bw_type.len = session->bw_type.len;
1170
0
    memcpy( p, session->bw_type.s, session->bw_type.len);
1171
0
    p += session->bw_type.len;
1172
0
  }
1173
1174
0
  if (session->bw_width.len) {
1175
0
    clone_session->bw_width.s = p;
1176
0
    clone_session->bw_width.len = session->bw_width.len;
1177
0
    memcpy( p, session->bw_width.s, session->bw_width.len);
1178
0
    p += session->bw_width.len;
1179
0
  }
1180
1181
0
  return clone_session;
1182
0
error:
1183
0
  free_cloned_sdp_session(clone_session);
1184
0
  return NULL;
1185
0
}
1186
1187
sdp_info_t * clone_sdp_info(sdp_info_t *sdp_info)
1188
0
{
1189
0
  sdp_info_t *clone_sdp_info;
1190
0
  sdp_session_cell_t *clone_session, *prev_clone_session, *session;
1191
0
  int i, len;
1192
1193
0
  if (sdp_info==NULL) {
1194
0
    LM_ERR("no sdp to clone\n");
1195
0
    return NULL;
1196
0
  }
1197
0
  if (sdp_info->sessions_num == 0) {
1198
0
    LM_ERR("no sessions to clone\n");
1199
0
    return NULL;
1200
0
  }
1201
1202
0
  len = sizeof(sdp_info_t);
1203
0
  clone_sdp_info = (sdp_info_t*)shm_malloc(len);
1204
0
  if (clone_sdp_info == NULL) {
1205
0
    LM_ERR("no more shm mem (%d)\n",len);
1206
0
    return NULL;
1207
0
  }
1208
0
  LM_DBG("clone_sdp_info: %p\n", clone_sdp_info);
1209
0
  memset( clone_sdp_info, 0, len);
1210
0
  LM_DBG("we have %d sessions\n", sdp_info->sessions_num);
1211
0
  clone_sdp_info->sessions_num = sdp_info->sessions_num;
1212
0
  clone_sdp_info->streams_num = sdp_info->streams_num;
1213
1214
0
  session=sdp_info->sessions;
1215
0
  clone_session=clone_sdp_session_cell(session);
1216
0
  if (clone_session==NULL) {
1217
0
    goto error;
1218
0
  }
1219
0
  clone_sdp_info->sessions=clone_session;
1220
0
  prev_clone_session=clone_session;
1221
0
  session=session->next;
1222
0
  for (i=1;i<sdp_info->sessions_num;i++) {
1223
0
    clone_session=clone_sdp_session_cell(session);
1224
0
    if (clone_session==NULL) {
1225
0
      goto error;
1226
0
    }
1227
0
    prev_clone_session->next=clone_session;
1228
0
    prev_clone_session=clone_session;
1229
0
    session=session->next;
1230
0
  }
1231
1232
0
  return clone_sdp_info;
1233
0
error:
1234
0
  free_cloned_sdp(clone_sdp_info);
1235
0
  return NULL;
1236
0
}
1237