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