Coverage Report

Created: 2025-04-11 06:59

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