Browse code

core: parser sdp - check if delimiter exceeds body limit

Daniel-Constantin Mierla authored on 16/12/2021 09:01:34
Showing 1 changed files
... ...
@@ -645,12 +645,16 @@ static int parse_mixed_content(str *mixed_body, str delimiter, sdp_info_t* _sdp)
645 645
 		d1p = d2p;
646 646
 		if (d1p == NULL || d1p >= bodylimit)
647 647
 			break; /* No applications left */
648
+		if(d1p + delimiter.len + 2 > bodylimit) {
649
+			LM_ERR("failed parsing [%.*s]\n", mixed_body->len, mixed_body->s);
650
+			return -1;
651
+		}
648 652
 		d2p = find_next_sdp_line_delimiter(d1p, bodylimit, delimiter, bodylimit);
649 653
 		/* d2p is text limit for application parsing */
650
-		memset(&hf,0, sizeof(struct hdr_field));
654
+		memset(&hf, 0, sizeof(struct hdr_field));
651 655
 		rest = eat_line(d1p + delimiter.len + 2, d2p - d1p - delimiter.len - 2);
652 656
 		if ( rest > d2p ) {
653
-			LM_ERR("Unparsable <%.*s>\n", (int)(d2p-d1p), d1p);
657
+			LM_ERR("unparsable [%.*s]\n", (int)(d2p-d1p), d1p);
654 658
 			return -1;
655 659
 		}
656 660
 		no_eoh_found = 1;
Browse code

core: parse session sendrecv_mode in sdp

- some user agents send a=sendonly as session attribute which apply to all media streams

Luis Azedo authored on 05/08/2021 11:28:04 • Daniel-Constantin Mierla committed on 11/08/2021 17:38:16
Showing 1 changed files
... ...
@@ -453,6 +453,18 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
453 453
 		extract_bwidth(&tmpstr1, &session->bw_type, &session->bw_width);
454 454
 	}
455 455
 
456
+	/* Find sendrecv_mode between session begin and first media.
457
+	 * parse session attributes to check is_on_hold for a= for all medias. */
458
+	a1p = find_first_sdp_line(o1p, m1p, 'a', NULL);
459
+	while (a1p) {
460
+		tmpstr1.s = a1p;
461
+		tmpstr1.len = m1p - a1p;
462
+		if (extract_sendrecv_mode(&tmpstr1, &session->sendrecv_mode, &session->is_on_hold) == 0) {
463
+			break;
464
+		}
465
+		a1p = find_next_sdp_line(a1p, m1p, 'a', NULL);
466
+	}
467
+
456 468
 	/* Have session. Iterate media descriptions in session */
457 469
 	m2p = m1p;
458 470
 	stream_num = 0;
Browse code

core: parser sdp - shorten debug message with sdp line

- was printing the rest of the body, print now max 20 chars

Daniel-Constantin Mierla authored on 03/08/2021 06:51:11
Showing 1 changed files
... ...
@@ -584,7 +584,8 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
584 584
 				a1p = stream->path.s + stream->path.len;
585 585
 			} else {
586 586
 				/* unknown a= line, ignore -- jump over it */
587
-				LM_DBG("ignoring unknown type in a= line: `%.*s'\n", tmpstr1.len, tmpstr1.s);
587
+				LM_DBG("ignoring unknown type in a= line: `%.*s...'\n",
588
+						(tmpstr1.len>20)?20:tmpstr1.len, tmpstr1.s);
588 589
 				a1p += 2;
589 590
 			}
590 591
 
Browse code

core: rename sdp parser USE_PKG_MEM and USE_SHM_MEM #define, prevent core mix-up

Henning Westerholt authored on 27/12/2018 16:08:25
Showing 1 changed files
... ...
@@ -35,8 +35,8 @@
35 35
 #include "sdp.h"
36 36
 #include "sdp_helpr_funcs.h"
37 37
 
38
-#define USE_PKG_MEM 0
39
-#define USE_SHM_MEM 1
38
+#define SDP_USE_PKG_MEM 0
39
+#define SDP_USE_SHM_MEM 1
40 40
 
41 41
 #define HOLD_IP_STR "0.0.0.0"
42 42
 #define HOLD_IP_LEN 7
... ...
@@ -179,18 +179,18 @@ static inline sdp_payload_attr_t** init_p_payload_attr(sdp_stream_cell_t* _strea
179 179
 		LM_ERR("Invalid number of payloads\n");
180 180
 		return NULL;
181 181
 	}
182
-	if (pkg == USE_PKG_MEM) {
182
+	if (pkg == SDP_USE_PKG_MEM) {
183 183
 		_stream->p_payload_attr = (sdp_payload_attr_t**)pkg_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
184
-	} else if (pkg == USE_SHM_MEM) {
184
+	} else if (pkg == SDP_USE_SHM_MEM) {
185 185
 		_stream->p_payload_attr = (sdp_payload_attr_t**)shm_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
186 186
 	} else {
187 187
 		LM_ERR("undefined memory type\n");
188 188
 		return NULL;
189 189
 	}
190 190
 	if (_stream->p_payload_attr == NULL) {
191
-		if (pkg == USE_PKG_MEM) {
191
+		if (pkg == SDP_USE_PKG_MEM) {
192 192
 			PKG_MEM_ERROR;
193
-		} else if (pkg == USE_SHM_MEM) {
193
+		} else if (pkg == SDP_USE_SHM_MEM) {
194 194
 			SHM_MEM_ERROR;
195 195
 		}
196 196
 		return NULL;
... ...
@@ -531,7 +531,7 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
531 531
 			}
532 532
 
533 533
 			/* Initialize fast access pointers */
534
-			if (NULL == init_p_payload_attr(stream, USE_PKG_MEM)) {
534
+			if (NULL == init_p_payload_attr(stream, SDP_USE_PKG_MEM)) {
535 535
 				return -1;
536 536
 			}
537 537
 			parse_payload_attr = 1;
... ...
@@ -1082,7 +1082,7 @@ sdp_stream_cell_t * clone_sdp_stream_cell(sdp_stream_cell_t *stream)
1082 1082
 
1083 1083
 	clone_stream->payloads_num = stream->payloads_num;
1084 1084
 	if (clone_stream->payloads_num) {
1085
-		if (NULL == init_p_payload_attr(clone_stream, USE_SHM_MEM)) {
1085
+		if (NULL == init_p_payload_attr(clone_stream, SDP_USE_SHM_MEM)) {
1086 1086
 			goto error;
1087 1087
 		}
1088 1088
 	}
... ...
@@ -1319,3 +1319,5 @@ error:
1319 1319
 	return NULL;
1320 1320
 }
1321 1321
 
1322
+#undef SDP_USE_PKG_MEM
1323
+#undef SDP_USE_SHM_MEM
Browse code

core: use generic PKG_MEM_ERROR, SHM_ERROR and _CRITICAL helper defines in core

- refactoring of the core to use generic PKG_MEM_ERROR, SHM_ERROR,
PKG_MEM_CRITICAL, SHM_MEM_CRITICAL and SYS_MEM_ERROR helper defines
- unify many different error messages in different spellings
- add a few missing error handler for allocation errors after (found
with a complete review of all memory allocation functions in core)
- no other functional changes, change has been reviewed two times

Henning Westerholt authored on 23/12/2018 21:31:03
Showing 1 changed files
... ...
@@ -50,7 +50,7 @@ static inline int new_sdp(struct sip_msg* _m)
50 50
 
51 51
 	sdp = (sdp_info_t*)pkg_malloc(sizeof(sdp_info_t));
52 52
 	if (sdp == NULL) {
53
-		LM_ERR("No memory left\n");
53
+		PKG_MEM_ERROR;
54 54
 		return -1;
55 55
 	}
56 56
 	memset( sdp, 0, sizeof(sdp_info_t));
... ...
@@ -72,7 +72,7 @@ static inline sdp_session_cell_t *add_sdp_session(sdp_info_t* _sdp, int session_
72 72
 	len = sizeof(sdp_session_cell_t);
73 73
 	session = (sdp_session_cell_t*)pkg_malloc(len);
74 74
 	if (session == NULL) {
75
-		LM_ERR("No memory left\n");
75
+		PKG_MEM_ERROR;
76 76
 		return NULL;
77 77
 	}
78 78
 	memset( session, 0, len);
... ...
@@ -103,7 +103,7 @@ static inline sdp_stream_cell_t *add_sdp_stream(sdp_session_cell_t* _session, in
103 103
 	len = sizeof(sdp_stream_cell_t);
104 104
 	stream = (sdp_stream_cell_t*)pkg_malloc(len);
105 105
 	if (stream == NULL) {
106
-		LM_ERR("No memory left\n");
106
+		PKG_MEM_ERROR;
107 107
 		return NULL;
108 108
 	}
109 109
 	memset( stream, 0, len);
... ...
@@ -144,7 +144,7 @@ static inline sdp_payload_attr_t *add_sdp_payload(sdp_stream_cell_t* _stream, in
144 144
 	len = sizeof(sdp_payload_attr_t);
145 145
 	payload_attr = (sdp_payload_attr_t*)pkg_malloc(len);
146 146
 	if (payload_attr == NULL) {
147
-		LM_ERR("No memory left\n");
147
+		PKG_MEM_ERROR;
148 148
 		return NULL;
149 149
 	}
150 150
 	memset( payload_attr, 0, len);
... ...
@@ -188,7 +188,11 @@ static inline sdp_payload_attr_t** init_p_payload_attr(sdp_stream_cell_t* _strea
188 188
 		return NULL;
189 189
 	}
190 190
 	if (_stream->p_payload_attr == NULL) {
191
-		LM_ERR("No memory left\n");
191
+		if (pkg == USE_PKG_MEM) {
192
+			PKG_MEM_ERROR;
193
+		} else if (pkg == USE_SHM_MEM) {
194
+			SHM_MEM_ERROR;
195
+		}
192 196
 		return NULL;
193 197
 	}
194 198
 
... ...
@@ -986,7 +990,7 @@ sdp_payload_attr_t * clone_sdp_payload_attr(sdp_payload_attr_t *attr)
986 990
 			attr->fmtp_string.len;
987 991
 	clone_attr = (sdp_payload_attr_t*)shm_malloc(len);
988 992
 	if (clone_attr == NULL) {
989
-		LM_ERR("no more shm mem (%d)\n",len);
993
+		SHM_MEM_ERROR;
990 994
 		return NULL;
991 995
 	}
992 996
 	memset( clone_attr, 0, len);
... ...
@@ -1058,7 +1062,7 @@ sdp_stream_cell_t * clone_sdp_stream_cell(sdp_stream_cell_t *stream)
1058 1062
 			stream->rtcp_port.len;
1059 1063
 	clone_stream = (sdp_stream_cell_t*)shm_malloc(len);
1060 1064
 	if (clone_stream == NULL) {
1061
-		LM_ERR("no more shm mem (%d)\n",len);
1065
+		SHM_MEM_ERROR;
1062 1066
 		return NULL;
1063 1067
 	}
1064 1068
 	memset( clone_stream, 0, len);
... ...
@@ -1188,7 +1192,7 @@ sdp_session_cell_t * clone_sdp_session_cell(sdp_session_cell_t *session)
1188 1192
 		session->bw_width.len;
1189 1193
 	clone_session = (sdp_session_cell_t*)shm_malloc(len);
1190 1194
 	if (clone_session == NULL) {
1191
-		LM_ERR("no more shm mem (%d)\n",len);
1195
+		SHM_MEM_ERROR;
1192 1196
 		return NULL;
1193 1197
 	}
1194 1198
 	memset( clone_session, 0, len);
... ...
@@ -1282,7 +1286,7 @@ sdp_info_t * clone_sdp_info(struct sip_msg* _m)
1282 1286
 	len = sizeof(sdp_info_t);
1283 1287
 	clone_sdp_info = (sdp_info_t*)shm_malloc(len);
1284 1288
 	if (clone_sdp_info == NULL) {
1285
-		LM_ERR("no more shm mem (%d)\n",len);
1289
+		SHM_MEM_ERROR;
1286 1290
 		return NULL;
1287 1291
 	}
1288 1292
 	LM_DBG("clone_sdp_info: %p\n", clone_sdp_info);
Browse code

core: parse SDP origin line sess-version field

Mikko Lehto authored on 08/06/2018 09:28:39
Showing 1 changed files
... ...
@@ -410,6 +410,14 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
410 410
 	session = add_sdp_session(_sdp, session_num, cnt_disp);
411 411
 	if (session == NULL) return -1;
412 412
 
413
+	/* Get sess-version */
414
+	tmpstr1.s = o1p;
415
+	tmpstr1.len = eat_line(o1p,m1p-o1p) - o1p;
416
+	if ( extract_sess_version(&tmpstr1, &session->o_sess_version) == -1 ) {
417
+		LM_ERR("can't extract origin sess-version from the message\n");
418
+		return -1;
419
+	}
420
+
413 421
 	/* Get origin IP */
414 422
 	tmpstr1.s = o1p;
415 423
 	tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
Browse code

core: fix typos

Thanks, lintian
> I: kamailio: spelling-error-in-binary usr/sbin/kamailio lenght length
> I: kamailio: spelling-error-in-binary usr/sbin/kamailio orderd ordered
> I: kamailio: spelling-error-in-binary usr/sbin/kamailio uknown unknown

Victor Seva authored on 08/02/2018 08:53:43
Showing 1 changed files
... ...
@@ -371,7 +371,7 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
371 371
 	str fmtp_string;
372 372
 	str remote_candidates = {"a:remote-candidates:", 20};
373 373
 
374
-	/* hook the start and lenght of sdp body inside structure
374
+	/* hook the start and length of sdp body inside structure
375 375
 	 * - shorcut useful for multi-part bodies and sdp operations
376 376
 	 */
377 377
 	_sdp->text = *sdp_body;
Browse code

parser/sdp: distinguish between RFC2543 and RFC3264 media hold type

Ovidiu Sas authored on 02/02/2018 19:23:08
Showing 1 changed files
... ...
@@ -584,11 +584,11 @@ static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_
584 584
 			if (stream->ip_addr.s && stream->ip_addr.len) {
585 585
 				if (stream->ip_addr.len == HOLD_IP_LEN &&
586 586
 					strncmp(stream->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
587
-					stream->is_on_hold = 1;
587
+					stream->is_on_hold = RFC2543_HOLD;
588 588
 			} else if (session->ip_addr.s && session->ip_addr.len) {
589 589
 				if (session->ip_addr.len == HOLD_IP_LEN &&
590 590
 					strncmp(session->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
591
-					stream->is_on_hold = 1;
591
+					stream->is_on_hold = RFC2543_HOLD;
592 592
 			}
593 593
 		}
594 594
 		++stream_num;
Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,1309 @@
1
+/*
2
+ * SDP parser interface
3
+ *
4
+ * Copyright (C) 2008-2009 SOMA Networks, INC.
5
+ * Copyright (C) 2010 VoIP Embedded, Inc
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without
8
+ * modification, are permitted provided that the following conditions are met:
9
+ *
10
+ *  1. Redistributions of source code must retain the above copyright notice,
11
+ *  this list of conditions and the following disclaimer.
12
+ *  2. Redistributions in binary form must reproduce the above copyright
13
+ *  notice, this list of conditions and the following disclaimer in the
14
+ *  documentation and/or other materials provided with the distribution.
15
+ *
16
+ * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY EXPRESS OR
17
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19
+ * EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
20
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+ *
27
+ */
28
+
29
+
30
+#include "../../ut.h"
31
+#include "../../mem/mem.h"
32
+#include "../../mem/shm_mem.h"
33
+#include "../parser_f.h"
34
+#include "../parse_content.h"
35
+#include "sdp.h"
36
+#include "sdp_helpr_funcs.h"
37
+
38
+#define USE_PKG_MEM 0
39
+#define USE_SHM_MEM 1
40
+
41
+#define HOLD_IP_STR "0.0.0.0"
42
+#define HOLD_IP_LEN 7
43
+
44
+/**
45
+ * Creates and initialize a new sdp_info structure
46
+ */
47
+static inline int new_sdp(struct sip_msg* _m)
48
+{
49
+	sdp_info_t* sdp;
50
+
51
+	sdp = (sdp_info_t*)pkg_malloc(sizeof(sdp_info_t));
52
+	if (sdp == NULL) {
53
+		LM_ERR("No memory left\n");
54
+		return -1;
55
+	}
56
+	memset( sdp, 0, sizeof(sdp_info_t));
57
+	sdp->type = MSG_BODY_SDP;
58
+	sdp->free = (free_msg_body_f)free_sdp;
59
+	_m->body = (msg_body_t*)sdp;
60
+
61
+	return 0;
62
+}
63
+
64
+/**
65
+ * Alocate a new session cell.
66
+ */
67
+static inline sdp_session_cell_t *add_sdp_session(sdp_info_t* _sdp, int session_num, str* cnt_disp)
68
+{
69
+	sdp_session_cell_t *session;
70
+	int len;
71
+
72
+	len = sizeof(sdp_session_cell_t);
73
+	session = (sdp_session_cell_t*)pkg_malloc(len);
74
+	if (session == NULL) {
75
+		LM_ERR("No memory left\n");
76
+		return NULL;
77
+	}
78
+	memset( session, 0, len);
79
+
80
+	session->session_num = session_num;
81
+	if (cnt_disp != NULL) {
82
+		session->cnt_disp.s = cnt_disp->s;
83
+		session->cnt_disp.len = cnt_disp->len;
84
+	}
85
+
86
+	/* Insert the new session */
87
+	session->next = _sdp->sessions;
88
+	_sdp->sessions = session;
89
+	_sdp->sessions_num++;
90
+
91
+	return session;
92
+}
93
+
94
+/**
95
+ * Allocate a new stream cell.
96
+ */
97
+static inline sdp_stream_cell_t *add_sdp_stream(sdp_session_cell_t* _session, int stream_num,
98
+		str* media, str* port, str* transport, str* payloads, int is_rtp, int pf, str* sdp_ip)
99
+{
100
+	sdp_stream_cell_t *stream;
101
+	int len;
102
+
103
+	len = sizeof(sdp_stream_cell_t);
104
+	stream = (sdp_stream_cell_t*)pkg_malloc(len);
105
+	if (stream == NULL) {
106
+		LM_ERR("No memory left\n");
107
+		return NULL;
108
+	}
109
+	memset( stream, 0, len);
110
+
111
+	stream->stream_num = stream_num;
112
+
113
+	stream->media.s = media->s;
114
+	stream->media.len = media->len;
115
+	stream->port.s = port->s;
116
+	stream->port.len = port->len;
117
+	stream->transport.s = transport->s;
118
+	stream->transport.len = transport->len;
119
+	stream->payloads.s = payloads->s;
120
+	stream->payloads.len = payloads->len;
121
+
122
+	stream->is_rtp = is_rtp;
123
+
124
+	stream->pf = pf;
125
+	stream->ip_addr.s = sdp_ip->s;
126
+	stream->ip_addr.len = sdp_ip->len;
127
+
128
+	/* Insert the new stream */
129
+	stream->next = _session->streams;
130
+	_session->streams = stream;
131
+	_session->streams_num++;
132
+
133
+	return stream;
134
+}
135
+
136
+/**
137
+ * Allocate a new payload.
138
+ */
139
+static inline sdp_payload_attr_t *add_sdp_payload(sdp_stream_cell_t* _stream, int payload_num, str* payload)
140
+{
141
+	sdp_payload_attr_t *payload_attr;
142
+	int len;
143
+
144
+	len = sizeof(sdp_payload_attr_t);
145
+	payload_attr = (sdp_payload_attr_t*)pkg_malloc(len);
146
+	if (payload_attr == NULL) {
147
+		LM_ERR("No memory left\n");
148
+		return NULL;
149
+	}
150
+	memset( payload_attr, 0, len);
151
+
152
+	payload_attr->payload_num = payload_num;
153
+	payload_attr->rtp_payload.s = payload->s;
154
+	payload_attr->rtp_payload.len = payload->len;
155
+
156
+	/* Insert the new payload */
157
+	payload_attr->next = _stream->payload_attr;
158
+	_stream->payload_attr = payload_attr;
159
+	_stream->payloads_num++;
160
+
161
+	return payload_attr;
162
+}
163
+
164
+
165
+/**
166
+ * Initialize fast access pointers.
167
+ */
168
+static inline sdp_payload_attr_t** init_p_payload_attr(sdp_stream_cell_t* _stream, int pkg)
169
+{
170
+	int payloads_num, i;
171
+	sdp_payload_attr_t *payload;
172
+
173
+	if (_stream == NULL) {
174
+		LM_ERR("Invalid stream\n");
175
+		return NULL;
176
+	}
177
+	payloads_num = _stream->payloads_num;
178
+	if (payloads_num == 0) {
179
+		LM_ERR("Invalid number of payloads\n");
180
+		return NULL;
181
+	}
182
+	if (pkg == USE_PKG_MEM) {
183
+		_stream->p_payload_attr = (sdp_payload_attr_t**)pkg_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
184
+	} else if (pkg == USE_SHM_MEM) {
185
+		_stream->p_payload_attr = (sdp_payload_attr_t**)shm_malloc(payloads_num * sizeof(sdp_payload_attr_t*));
186
+	} else {
187
+		LM_ERR("undefined memory type\n");
188
+		return NULL;
189
+	}
190
+	if (_stream->p_payload_attr == NULL) {
191
+		LM_ERR("No memory left\n");
192
+		return NULL;
193
+	}
194
+
195
+	--payloads_num;
196
+	payload = _stream->payload_attr;
197
+	for (i=0;i<=payloads_num;i++) {
198
+		_stream->p_payload_attr[payloads_num-i] = payload;
199
+		payload = payload->next;
200
+	}
201
+
202
+	return _stream->p_payload_attr;
203
+}
204
+
205
+/*
206
+ * Setters ...
207
+ */
208
+
209
+void set_sdp_payload_attr(sdp_payload_attr_t *payload_attr, str *rtp_enc, str *rtp_clock, str *rtp_params)
210
+{
211
+	if (payload_attr == NULL) {
212
+		LM_ERR("Invalid payload location\n");
213
+		return;
214
+	}
215
+	payload_attr->rtp_enc.s = rtp_enc->s;
216
+	payload_attr->rtp_enc.len = rtp_enc->len;
217
+	payload_attr->rtp_clock.s = rtp_clock->s;
218
+	payload_attr->rtp_clock.len = rtp_clock->len;
219
+	payload_attr->rtp_params.s = rtp_params->s;
220
+	payload_attr->rtp_params.len = rtp_params->len;
221
+
222
+	return;
223
+}
224
+
225
+void set_sdp_payload_fmtp(sdp_payload_attr_t *payload_attr, str *fmtp_string )
226
+{
227
+	if (payload_attr == NULL) {
228
+		LM_ERR("Invalid payload location\n");
229
+		return;
230
+	}
231
+	payload_attr->fmtp_string.s = fmtp_string->s;
232
+	payload_attr->fmtp_string.len = fmtp_string->len;
233
+
234
+	return;
235
+}
236
+
237
+/*
238
+ * Getters ....
239
+ */
240
+int get_sdp_session_num(struct sip_msg* _m)
241
+{
242
+	if (_m->body == NULL) return 0;
243
+	if (_m->body->type != MSG_BODY_SDP) return 0;
244
+	return ((sdp_info_t*)_m->body)->sessions_num;
245
+}
246
+
247
+int get_sdp_stream_num(struct sip_msg* _m)
248
+{
249
+	if (_m->body == NULL) return 0;
250
+	if (_m->body->type != MSG_BODY_SDP) return 0;
251
+	return ((sdp_info_t*)_m->body)->streams_num;
252
+}
253
+
254
+sdp_session_cell_t* get_sdp_session_sdp(struct sdp_info* sdp, int session_num)
255
+{
256
+	sdp_session_cell_t *session;
257
+
258
+	session = sdp->sessions;
259
+	if (session_num >= sdp->sessions_num) return NULL;
260
+	while (session) {
261
+		if (session->session_num == session_num) return session;
262
+		session = session->next;
263
+	}
264
+	return NULL;
265
+}
266
+
267
+sdp_session_cell_t* get_sdp_session(struct sip_msg* _m, int session_num)
268
+{
269
+	if (_m->body == NULL) return NULL;
270
+	if (_m->body->type != MSG_BODY_SDP) return NULL;
271
+	return get_sdp_session_sdp((sdp_info_t*)_m->body, session_num);
272
+}
273
+
274
+
275
+sdp_stream_cell_t* get_sdp_stream_sdp(struct sdp_info* sdp, int session_num, int stream_num)
276
+{
277
+	sdp_session_cell_t *session;
278
+	sdp_stream_cell_t *stream;
279
+
280
+	if (sdp==NULL) return NULL;
281
+	if (session_num >= sdp->sessions_num) return NULL;
282
+	session = sdp->sessions;
283
+	while (session) {
284
+		if (session->session_num == session_num) {
285
+			if (stream_num >= session->streams_num) return NULL;
286
+			stream = session->streams;
287
+			while (stream) {
288
+				if (stream->stream_num == stream_num) return stream;
289
+				stream = stream->next;
290
+			}
291
+			break;
292
+		} else {
293
+			session = session->next;
294
+		}
295
+	}
296
+
297
+	return NULL;
298
+}
299
+
300
+sdp_stream_cell_t* get_sdp_stream(struct sip_msg* _m, int session_num, int stream_num)
301
+{
302
+	if (_m->body == NULL) return NULL;
303
+	if (_m->body->type != MSG_BODY_SDP) return NULL;
304
+	return get_sdp_stream_sdp((sdp_info_t*)_m->body, session_num, stream_num);
305
+}
306
+
307
+
308
+sdp_payload_attr_t* get_sdp_payload4payload(sdp_stream_cell_t *stream, str *rtp_payload)
309
+{
310
+	sdp_payload_attr_t *payload;
311
+	int i;
312
+
313
+	if (stream == NULL) {
314
+		LM_ERR("Invalid stream location\n");
315
+		return NULL;
316
+	}
317
+	if (stream->p_payload_attr == NULL) {
318
+		LM_ERR("Invalid access pointer to payloads\n");
319
+		return NULL;
320
+	}
321
+
322
+	for (i=0;i<stream->payloads_num;i++) {
323
+		payload = stream->p_payload_attr[i];
324
+		if (rtp_payload->len == payload->rtp_payload.len &&
325
+			(strncmp(rtp_payload->s, payload->rtp_payload.s, rtp_payload->len)==0)) {
326
+			return payload;
327
+		}
328
+	}
329
+
330
+	return NULL;
331
+}
332
+
333
+sdp_payload_attr_t* get_sdp_payload4index(sdp_stream_cell_t *stream, int index)
334
+{
335
+	if (stream == NULL) {
336
+		LM_ERR("Invalid stream location\n");
337
+		return NULL;
338
+	}
339
+	if (stream->p_payload_attr == NULL) {
340
+		LM_ERR("Invalid access pointer to payloads\n");
341
+		return NULL;
342
+	}
343
+	if (index >= stream->payloads_num) {
344
+		LM_ERR("Out of range index [%d] for payload\n", index);
345
+		return NULL;
346
+	}
347
+
348
+	return stream->p_payload_attr[index];
349
+}
350
+
351
+
352
+/**
353
+ * SDP parser method.
354
+ */
355
+static int parse_sdp_session(str *sdp_body, int session_num, str *cnt_disp, sdp_info_t* _sdp)
356
+{
357
+	str body = *sdp_body;
358
+	str sdp_ip = {NULL,0};
359
+	str sdp_media, sdp_port, sdp_transport, sdp_payload;
360
+	str payload;
361
+	str rtp_payload, rtp_enc, rtp_clock, rtp_params;
362
+	int is_rtp;
363
+	char *bodylimit;
364
+	char *v1p, *o1p, *m1p, *m2p, *c1p, *c2p, *a1p, *a2p, *b1p;
365
+	str tmpstr1;
366
+	int stream_num, payloadnum, pf;
367
+	sdp_session_cell_t *session;
368
+	sdp_stream_cell_t *stream;
369
+	sdp_payload_attr_t *payload_attr;
370
+	int parse_payload_attr;
371
+	str fmtp_string;
372
+	str remote_candidates = {"a:remote-candidates:", 20};
373
+
374
+	/* hook the start and lenght of sdp body inside structure
375
+	 * - shorcut useful for multi-part bodies and sdp operations
376
+	 */
377
+	_sdp->text = *sdp_body;
378
+	pf = AF_INET;
379
+
380
+	/*
381
+	 * Parsing of SDP body.
382
+	 * Each session starts with v-line and each session may contain a few
383
+	 * media descriptions (each starts with m-line).
384
+	 * We have to change ports in m-lines, and also change IP addresses in
385
+	 * c-lines which can be placed either in session header (fallback for
386
+	 * all medias) or media description.
387
+	 * Ports should be allocated for any media. IPs all should be changed
388
+	 * to the same value (RTP proxy IP), so we can change all c-lines
389
+	 * unconditionally.
390
+	 */
391
+	bodylimit = body.s + body.len;
392
+	v1p = find_sdp_line(body.s, bodylimit, 'v');
393
+	if (v1p == NULL) {
394
+		LM_ERR("no sessions in SDP\n");
395
+		return -1;
396
+	}
397
+	/* get session origin */
398
+	o1p = find_sdp_line(v1p, bodylimit, 'o');
399
+	if (o1p == NULL) {
400
+		LM_ERR("no o= in session\n");
401
+		return -1;
402
+	}
403
+	/* Have this session media description? */
404
+	m1p = find_sdp_line(o1p, bodylimit, 'm');
405
+	if (m1p == NULL) {
406
+		LM_ERR("no m= in session\n");
407
+		return -1;
408
+	}
409
+	/* Allocate a session cell */
410
+	session = add_sdp_session(_sdp, session_num, cnt_disp);
411
+	if (session == NULL) return -1;
412
+
413
+	/* Get origin IP */
414
+	tmpstr1.s = o1p;
415
+	tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
416
+	if (extract_mediaip(&tmpstr1, &session->o_ip_addr, &session->o_pf,"o=") == -1) {
417
+		LM_ERR("can't extract origin media IP from the message\n");
418
+		return -1;
419
+	}
420
+
421
+	/* Find c1p only between session begin and first media.
422
+	 * c1p will give common c= for all medias. */
423
+	c1p = find_sdp_line(o1p, m1p, 'c');
424
+
425
+	if (c1p) {
426
+		/* Extract session address */
427
+		tmpstr1.s = c1p;
428
+		tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
429
+		if (extract_mediaip(&tmpstr1, &session->ip_addr, &session->pf,"c=") == -1) {
430
+			LM_ERR("can't extract common media IP from the message\n");
431
+			return -1;
432
+		}
433
+	}
434
+
435
+	/* Find b1p only between session begin and first media.
436
+	 * b1p will give common b= for all medias. */
437
+	b1p = find_sdp_line(o1p, m1p, 'b');
438
+	if (b1p) {
439
+		tmpstr1.s = b1p;
440
+		tmpstr1.len = m1p - b1p;
441
+		extract_bwidth(&tmpstr1, &session->bw_type, &session->bw_width);
442
+	}
443
+
444
+	/* Have session. Iterate media descriptions in session */
445
+	m2p = m1p;
446
+	stream_num = 0;
447
+	for (;;) {
448
+		m1p = m2p; 
449
+		if (m1p == NULL || m1p >= bodylimit)
450
+			break;
451
+		m2p = find_next_sdp_line(m1p, bodylimit, 'm', bodylimit);
452
+		/* c2p will point to per-media "c=" */
453
+		c2p = find_sdp_line(m1p, m2p, 'c');
454
+
455
+		sdp_ip.s = NULL;
456
+		sdp_ip.len = 0;
457
+		if (c2p) {
458
+			/* Extract stream address */
459
+			tmpstr1.s = c2p;
460
+			tmpstr1.len = bodylimit - tmpstr1.s; /* limit is session limit text */
461
+			if (extract_mediaip(&tmpstr1, &sdp_ip, &pf,"c=") == -1) {
462
+				LM_ERR("can't extract media IP from the message\n");
463
+				return -1;
464
+			}
465
+		} else {
466
+			if (!c1p) {
467
+				/* No "c=" */
468
+				LM_ERR("can't find media IP in the message\n");
469
+				return -1;
470
+			}
471
+		}
472
+
473
+		/* Extract the port on sdp_port */
474
+		tmpstr1.s = m1p;
475
+		tmpstr1.len = m2p - m1p;
476
+		if (extract_media_attr(&tmpstr1, &sdp_media, &sdp_port, &sdp_transport, &sdp_payload, &is_rtp) == -1) {
477
+			LM_ERR("can't extract media attr from the message\n");
478
+			return -1;
479
+		}
480
+
481
+		/* Allocate a stream cell */
482
+		stream = add_sdp_stream(session, stream_num, &sdp_media, &sdp_port, &sdp_transport, &sdp_payload, is_rtp, pf, &sdp_ip);
483
+		if (stream == 0) return -1;
484
+
485
+        /* Store fast access ptr to raw stream */
486
+        stream->raw_stream.s = tmpstr1.s; 
487
+        stream->raw_stream.len = tmpstr1.len;
488
+                
489
+		/* increment total number of streams */
490
+		_sdp->streams_num++;
491
+
492
+		/* b1p will point to per-media "b=" */
493
+		b1p = find_sdp_line(m1p, m2p, 'b');
494
+		if (b1p) {
495
+			tmpstr1.s = b1p;
496
+			tmpstr1.len = m2p - b1p;
497
+			extract_bwidth(&tmpstr1, &stream->bw_type, &stream->bw_width);
498
+		}
499
+
500
+		/* Parsing the payloads */
501
+		tmpstr1.s = sdp_payload.s;
502
+		tmpstr1.len = sdp_payload.len;
503
+		payloadnum = 0;
504
+		if (tmpstr1.len != 0) {
505
+			for (;;) {
506
+				a1p = eat_token_end(tmpstr1.s, tmpstr1.s + tmpstr1.len);
507
+				payload.s = tmpstr1.s;
508
+				payload.len = a1p - tmpstr1.s;
509
+				payload_attr = add_sdp_payload(stream, payloadnum, &payload);
510
+				if (payload_attr == NULL) return -1;
511
+				tmpstr1.len -= payload.len;
512
+				tmpstr1.s = a1p;
513
+				a2p = eat_space_end(tmpstr1.s, tmpstr1.s + tmpstr1.len);
514
+				tmpstr1.len -= a2p - a1p;
515
+				tmpstr1.s = a2p;
516
+				if (a1p >= tmpstr1.s)
517
+					break;
518
+				payloadnum++;
519
+			}
520
+
521
+			/* Initialize fast access pointers */
522
+			if (NULL == init_p_payload_attr(stream, USE_PKG_MEM)) {
523
+				return -1;
524
+			}
525
+			parse_payload_attr = 1;
526
+		} else {
527
+			parse_payload_attr = 0;
528
+		}
529
+
530
+		payload_attr = 0;
531
+		/* Let's figure out the atributes */
532
+		a1p = find_sdp_line(m1p, m2p, 'a');
533
+		a2p = a1p;
534
+		for (;;) {
535
+			a1p = a2p;
536
+			if (a1p == NULL || a1p >= m2p)
537
+				break;
538
+			tmpstr1.s = a2p;
539
+			tmpstr1.len = m2p - a2p;
540
+
541
+			if (parse_payload_attr && extract_ptime(&tmpstr1, &stream->ptime) == 0) {
542
+				a1p = stream->ptime.s + stream->ptime.len;
543
+			} else if (parse_payload_attr && extract_sendrecv_mode(&tmpstr1,
544
+					&stream->sendrecv_mode, &stream->is_on_hold) == 0) {
545
+				a1p = stream->sendrecv_mode.s + stream->sendrecv_mode.len;
546
+			} else if (parse_payload_attr && extract_rtpmap(&tmpstr1, &rtp_payload, &rtp_enc, &rtp_clock, &rtp_params) == 0) {
547
+				if (rtp_params.len != 0 && rtp_params.s != NULL) {
548
+					a1p = rtp_params.s + rtp_params.len;
549
+				} else {
550
+					a1p = rtp_clock.s + rtp_clock.len;
551
+				}
552
+				payload_attr = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &rtp_payload);
553
+				set_sdp_payload_attr(payload_attr, &rtp_enc, &rtp_clock, &rtp_params);
554
+			} else if (extract_rtcp(&tmpstr1, &stream->rtcp_port) == 0) {
555
+				a1p = stream->rtcp_port.s + stream->rtcp_port.len;
556
+			} else if (parse_payload_attr && extract_fmtp(&tmpstr1,&rtp_payload,&fmtp_string) == 0){
557
+				a1p = fmtp_string.s + fmtp_string.len;
558
+				payload_attr = (sdp_payload_attr_t*)get_sdp_payload4payload(stream, &rtp_payload);
559
+				set_sdp_payload_fmtp(payload_attr, &fmtp_string);
560
+			} else if (parse_payload_attr && extract_candidate(&tmpstr1, stream) == 0) {
561
+			        a1p += 2;
562
+			} else if (parse_payload_attr && extract_field(&tmpstr1, &stream->remote_candidates,
563
+								       remote_candidates) == 0) {
564
+			        a1p += 2;
565
+			} else if (extract_accept_types(&tmpstr1, &stream->accept_types) == 0) {
566
+				a1p = stream->accept_types.s + stream->accept_types.len;
567
+			} else if (extract_accept_wrapped_types(&tmpstr1, &stream->accept_wrapped_types) == 0) {
568
+				a1p = stream->accept_wrapped_types.s + stream->accept_wrapped_types.len;
569
+			} else if (extract_max_size(&tmpstr1, &stream->max_size) == 0) {
570
+				a1p = stream->max_size.s + stream->max_size.len;
571
+			} else if (extract_path(&tmpstr1, &stream->path) == 0) {
572
+				a1p = stream->path.s + stream->path.len;
573
+			} else {
574
+				/* unknown a= line, ignore -- jump over it */
575
+				LM_DBG("ignoring unknown type in a= line: `%.*s'\n", tmpstr1.len, tmpstr1.s);
576
+				a1p += 2;
577
+			}
578
+
579
+			a2p = find_first_sdp_line(a1p, m2p, 'a', m2p);
580
+		}
581
+		/* Let's detect if the media is on hold by checking
582
+		 * the good old "0.0.0.0" connection address */
583
+		if (!stream->is_on_hold) {
584
+			if (stream->ip_addr.s && stream->ip_addr.len) {
585
+				if (stream->ip_addr.len == HOLD_IP_LEN &&
586
+					strncmp(stream->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
587
+					stream->is_on_hold = 1;
588
+			} else if (session->ip_addr.s && session->ip_addr.len) {
589
+				if (session->ip_addr.len == HOLD_IP_LEN &&
590
+					strncmp(session->ip_addr.s, HOLD_IP_STR, HOLD_IP_LEN)==0)
591
+					stream->is_on_hold = 1;
592
+			}
593
+		}
594
+		++stream_num;
595
+	} /* Iterate medias/streams in session */
596
+	return 0;
597
+}
598
+
599
+static int parse_mixed_content(str *mixed_body, str delimiter, sdp_info_t* _sdp)
600
+{
601
+	int res, no_eoh_found, start_parsing;
602
+	char *bodylimit, *rest;
603
+	char *d1p, *d2p;
604
+	char *ret, *end;
605
+	unsigned int mime;
606
+	str cnt_disp;
607
+	int session_num;
608
+	struct hdr_field hf;
609
+
610
+	bodylimit = mixed_body->s + mixed_body->len;
611
+	d1p = find_sdp_line_delimiter(mixed_body->s, bodylimit, delimiter);
612
+	if (d1p == NULL) {
613
+		LM_ERR("empty multipart content\n");
614
+		return -1;
615
+	}
616
+	d2p = d1p;
617
+	session_num = 0;
618
+	for(;;) {
619
+		/* Per-application iteration */
620
+		d1p = d2p;
621
+		if (d1p == NULL || d1p >= bodylimit)
622
+			break; /* No applications left */
623
+		d2p = find_next_sdp_line_delimiter(d1p, bodylimit, delimiter, bodylimit);
624
+		/* d2p is text limit for application parsing */
625
+		memset(&hf,0, sizeof(struct hdr_field));
626
+		rest = eat_line(d1p + delimiter.len + 2, d2p - d1p - delimiter.len - 2);
627
+		if ( rest > d2p ) {
628
+			LM_ERR("Unparsable <%.*s>\n", (int)(d2p-d1p), d1p);
629
+			return -1;
630
+		}
631
+		no_eoh_found = 1;
632
+		start_parsing = 0;
633
+		/*LM_DBG("we need to parse this: <%.*s>\n", d2p-rest, rest); */
634
+		while( rest<d2p && no_eoh_found ) {
635
+			rest = get_sdp_hdr_field(rest, d2p, &hf);
636
+			switch (hf.type){
637
+			case HDR_EOH_T:
638
+				no_eoh_found = 0;
639
+				break;
640
+			case HDR_CONTENTTYPE_T:
641
+				end = hf.body.s + hf.body.len;
642
+				ret = decode_mime_type(hf.body.s, end , &mime);
643
+				if (ret==0)
644
+					return -1;
645
+				if (ret!=end) {
646
+					LM_ERR("the header CONTENT_TYPE contains "
647
+						"more then one mime type :-(!\n");
648
+					return -1;
649
+				}
650
+				if ((mime&0x00ff)==SUBTYPE_ALL || (mime>>16)==TYPE_ALL) {
651
+					LM_ERR("invalid mime with wildcard '*' in Content-Type hdr!\n");
652
+					return -1;
653
+				}
654
+			    	//LM_DBG("HDR_CONTENTTYPE_T: %d:%d %p-> <%.*s:%.*s>\n",mime&0x00ff,mime>>16,
655
+				//			hf.name.s,hf.name.len,hf.name.s,hf.body.len,hf.body.s);
656
+				if (((((unsigned int)mime)>>16) == TYPE_APPLICATION) && ((mime&0x00ff) == SUBTYPE_SDP)) {
657
+			    		/*LM_DBG("start_parsing: %d:%d\n",mime&0x00ff,mime>>16); */
658
+					start_parsing = 1;
659
+				}
660
+				break;
661
+			case HDR_CONTENTDISPOSITION_T:
662
+				cnt_disp.s = hf.body.s;
663
+				cnt_disp.len = hf.body.len;
664
+				break;
665
+			case HDR_ERROR_T:
666
+				return -1;
667
+				break;