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