Browse code

SDP document parser

Signed-off-by: Jan Janak <jan@iptel.org>

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