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