/src/opensips/parser/sdp/sdp_helpr_funcs.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * SDP parser helpers |
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 ported helper functions from nathelper module (osas) |
26 | | * 2008-04-22 integrated RFC4975 attributes - patch provided by Denis Bilenko (denik) |
27 | | * |
28 | | */ |
29 | | |
30 | | |
31 | | #include "../../ut.h" |
32 | | #include "../msg_parser.h" |
33 | | #include "../parser_f.h" |
34 | | #include "../parse_hname2.h" |
35 | | #include "sdp.h" |
36 | | |
37 | | |
38 | | static struct { |
39 | | const char *s; |
40 | | int len; |
41 | | int is_rtp; |
42 | | } sup_ptypes[] = { |
43 | | {.s = "rtp/avp", .len = 7, .is_rtp = 1}, |
44 | | {.s = "udptl", .len = 5, .is_rtp = 0}, |
45 | | {.s = "rtp/avpf", .len = 8, .is_rtp = 1}, |
46 | | {.s = "rtp/savp", .len = 8, .is_rtp = 1}, |
47 | | {.s = "rtp/savpf", .len = 9, .is_rtp = 1}, |
48 | | {.s = "udp", .len = 3, .is_rtp = 0}, |
49 | | {.s = "udp/bfcp", .len = 8, .is_rtp = 0}, |
50 | | {.s = NULL, .len = 0, .is_rtp = 0} |
51 | | }; |
52 | | |
53 | | |
54 | | int extract_rtpmap(str *body, |
55 | | str *rtpmap_payload, str *rtpmap_encoding, str *rtpmap_clockrate, str *rtpmap_parmas) |
56 | 0 | { |
57 | 0 | char *cp, *cp1; |
58 | 0 | int len; |
59 | | |
60 | | /* a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>] */ |
61 | | /* 1 9 10 12 14 */ |
62 | 0 | if (body->len < 14) |
63 | 0 | return -1; |
64 | | |
65 | 0 | if (strncasecmp(body->s, "a=rtpmap:", 9) !=0) { |
66 | | /*LM_DBG("We are not pointing to an a=rtpmap: attribute =>`%.*s'\n", body->len, body->s); */ |
67 | 0 | return -1; |
68 | 0 | } |
69 | | |
70 | 0 | cp1 = body->s; |
71 | |
|
72 | 0 | rtpmap_payload->s = cp1 + 9; /* skip `a=rtpmap:' */ |
73 | 0 | rtpmap_payload->len = eat_line(rtpmap_payload->s, body->s + body->len - |
74 | 0 | rtpmap_payload->s) - rtpmap_payload->s; |
75 | 0 | trim_len(rtpmap_payload->len, rtpmap_payload->s, *rtpmap_payload); |
76 | 0 | len = rtpmap_payload->len; |
77 | | |
78 | | /* */ |
79 | 0 | cp = eat_token_end(rtpmap_payload->s, rtpmap_payload->s + rtpmap_payload->len); |
80 | 0 | rtpmap_payload->len = cp - rtpmap_payload->s; |
81 | 0 | if (rtpmap_payload->len <= 0 || cp == rtpmap_payload->s) { |
82 | 0 | LM_ERR("no encoding in `a=rtpmap'\n"); |
83 | 0 | return -1; |
84 | 0 | } |
85 | 0 | len -= rtpmap_payload->len; |
86 | 0 | rtpmap_encoding->s = cp; |
87 | 0 | cp = eat_space_end(rtpmap_encoding->s, rtpmap_encoding->s + len); |
88 | 0 | len -= cp - rtpmap_encoding->s; |
89 | 0 | if (len <= 0 || cp == rtpmap_encoding->s) { |
90 | 0 | LM_ERR("no encoding in `a=rtpmap:'\n"); |
91 | 0 | return -1; |
92 | 0 | } |
93 | | |
94 | 0 | rtpmap_encoding->s = cp; |
95 | 0 | cp1 = (char*)l_memmem(cp, "/", len, 1); |
96 | 0 | len -= cp1 - cp; |
97 | 0 | if (cp1==NULL || len <= 1 || cp == cp1) { |
98 | 0 | LM_ERR("invalid encoding in `a=rtpmap' [%.*s]\n", |
99 | 0 | rtpmap_payload->len,rtpmap_payload->s); |
100 | 0 | return -1; |
101 | 0 | } |
102 | 0 | rtpmap_encoding->len = cp1 - cp; |
103 | | |
104 | | /* skip the '/' char */ |
105 | 0 | cp = cp1+1; |
106 | 0 | len--; |
107 | |
|
108 | 0 | cp1 = (char*)l_memmem(cp, "/", len, 1); |
109 | 0 | if (cp1 == NULL) { |
110 | 0 | rtpmap_clockrate->s = cp; |
111 | 0 | rtpmap_clockrate->len = len; |
112 | 0 | rtpmap_parmas->s = NULL; |
113 | 0 | rtpmap_parmas->len = 0; |
114 | 0 | } else { |
115 | 0 | rtpmap_clockrate->s = cp; |
116 | 0 | rtpmap_clockrate->len = cp1-cp; |
117 | 0 | len -= cp1 - cp; |
118 | 0 | if (len <= 1) { |
119 | 0 | LM_ERR("invalid encoding in `a=rtpmap' [%.*s]\n", |
120 | 0 | rtpmap_payload->len,rtpmap_payload->s); |
121 | 0 | return -1; |
122 | 0 | } |
123 | 0 | rtpmap_parmas->s = cp1 + 1; |
124 | 0 | rtpmap_parmas->len = len - 1; |
125 | 0 | } |
126 | 0 | return 0; |
127 | 0 | } |
128 | | |
129 | | int extract_custom_a_attr(str *body, str *payload, str *value) |
130 | 0 | { |
131 | 0 | char *cp, *p; |
132 | 0 | int len,i; |
133 | | |
134 | | /* a=<format> <format specific parameters> */ |
135 | | /* 10 for good luck ? */ |
136 | 0 | if (body->len < 10) { |
137 | 0 | LM_DBG("Too small body \n"); |
138 | 0 | return -1; |
139 | 0 | } |
140 | | |
141 | 0 | if (body->s[0] != 'a' && body->s[1] != '=') { |
142 | 0 | LM_DBG("We are not pointing to an a= attribute =>`%.*s'\n", body->len, body->s); |
143 | 0 | return -1; |
144 | 0 | } |
145 | | |
146 | 0 | i=0; |
147 | 0 | p=body->s; |
148 | 0 | while (i<body->len) { |
149 | 0 | if (*p == ':') |
150 | 0 | break; |
151 | 0 | p++; |
152 | 0 | i++; |
153 | 0 | } |
154 | |
|
155 | 0 | if (i==body->len) { |
156 | | /* no payload found */ |
157 | 0 | LM_DBG("no payload ID\n"); |
158 | 0 | return -1; |
159 | 0 | } |
160 | | |
161 | | /* payload ID starts after : */ |
162 | 0 | payload->s = p+1; |
163 | 0 | payload->len = eat_line(payload->s, body->s + body->len - |
164 | 0 | payload->s) - payload->s; |
165 | 0 | trim_len(payload->len, payload->s, *payload); |
166 | 0 | len = payload->len; |
167 | | |
168 | | /* */ |
169 | 0 | cp = eat_token_end(payload->s, payload->s + payload->len); |
170 | 0 | payload->len = cp - payload->s; |
171 | 0 | if (payload->len <= 0 || cp == payload->s) { |
172 | 0 | LM_ERR("no encoding \n"); |
173 | 0 | return -1; |
174 | 0 | } |
175 | | |
176 | 0 | len -= payload->len; |
177 | 0 | value->s = cp; |
178 | 0 | cp = eat_space_end(value->s, value->s + len); |
179 | 0 | len -= cp - value->s; |
180 | 0 | if (len <= 0 || cp == value->s) { |
181 | 0 | LM_DBG("no value in a= line \n"); |
182 | 0 | return -1; |
183 | 0 | } |
184 | | |
185 | 0 | value->s = cp; |
186 | |
|
187 | 0 | value->len = eat_line(value->s, body->s + body->len - |
188 | 0 | value->s) - value->s; |
189 | 0 | trim_len(value->len, value->s, *value); |
190 | |
|
191 | 0 | return 0; |
192 | 0 | } |
193 | | |
194 | | int extract_fmtp( str *body, str *fmtp_payload, str *fmtp_string ) |
195 | 0 | { |
196 | 0 | char *cp, *cp1; |
197 | 0 | int len; |
198 | | |
199 | | /* a=fmtp:<format> <format specific parameters> */ |
200 | | /* 1 7 8 10 */ |
201 | 0 | if (body->len < 10) |
202 | 0 | return -1; |
203 | | |
204 | 0 | if (strncasecmp(body->s, "a=fmtp:", 7) !=0) { |
205 | | /*LM_DBG("We are not pointing to an a=fmtp: attribute =>`%.*s'\n", body->len, body->s); */ |
206 | 0 | return -1; |
207 | 0 | } |
208 | | |
209 | 0 | cp1 = body->s; |
210 | |
|
211 | 0 | fmtp_payload->s = cp1 + 7; /* skip `a=fmtp:' */ |
212 | 0 | fmtp_payload->len = eat_line(fmtp_payload->s, body->s + body->len - |
213 | 0 | fmtp_payload->s) - fmtp_payload->s; |
214 | 0 | trim_len(fmtp_payload->len, fmtp_payload->s, *fmtp_payload); |
215 | 0 | len = fmtp_payload->len; |
216 | | |
217 | | /* */ |
218 | 0 | cp = eat_token_end(fmtp_payload->s, fmtp_payload->s + fmtp_payload->len); |
219 | 0 | fmtp_payload->len = cp - fmtp_payload->s; |
220 | 0 | if (fmtp_payload->len <= 0 || cp == fmtp_payload->s) { |
221 | 0 | LM_ERR("no encoding in `a=fmtp:'\n"); |
222 | 0 | return -1; |
223 | 0 | } |
224 | 0 | len -= fmtp_payload->len; |
225 | 0 | fmtp_string->s = cp; |
226 | 0 | cp = eat_space_end(fmtp_string->s, fmtp_string->s + len); |
227 | 0 | len -= cp - fmtp_string->s; |
228 | 0 | if (len <= 0 || cp == fmtp_string->s) { |
229 | 0 | LM_ERR("no encoding in `a=fmtp:'\n"); |
230 | 0 | return -1; |
231 | 0 | } |
232 | | |
233 | 0 | fmtp_string->s = cp; |
234 | |
|
235 | 0 | fmtp_string->len = eat_line(fmtp_string->s, body->s + body->len - |
236 | 0 | fmtp_string->s) - fmtp_string->s; |
237 | 0 | trim_len(fmtp_string->len, fmtp_string->s, *fmtp_string); |
238 | |
|
239 | 0 | return 0; |
240 | 0 | } |
241 | | |
242 | | /* generic method for attribute extraction |
243 | | * field must has format "a=attrname:" */ |
244 | | int extract_field(str *body, str *value, str field) |
245 | 0 | { |
246 | 0 | if (body->len < field.len) |
247 | 0 | return -1; |
248 | 0 | if (memcmp(body->s, field.s, field.len) !=0) { |
249 | | /*LM_DBG("We are not pointing to an %.* attribute =>`%.*s'\n", field.len, field.s, body->len, body->s); */ |
250 | 0 | return -1; |
251 | 0 | } |
252 | | |
253 | 0 | value->s = body->s + field.len; /* skip `a=attrname:' */ |
254 | 0 | value->len = eat_line(value->s, body->s + body->len - |
255 | 0 | value->s) - value->s; |
256 | 0 | trim_len(value->len, value->s, *value); |
257 | |
|
258 | 0 | return 0; |
259 | 0 | } |
260 | | |
261 | | |
262 | | int extract_ptime(str *body, str *ptime) |
263 | 0 | { |
264 | 0 | static const str field = str_init("a=ptime:"); |
265 | 0 | return extract_field(body, ptime, field); |
266 | 0 | } |
267 | | |
268 | | int extract_accept_types(str *body, str *accept_types) |
269 | 0 | { |
270 | 0 | static const str field = str_init("a=accept-types:"); |
271 | 0 | return extract_field(body, accept_types, field); |
272 | 0 | } |
273 | | |
274 | | int extract_accept_wrapped_types(str *body, str *accept_wrapped_types) |
275 | 0 | { |
276 | 0 | static const str field = str_init("a=accept-wrapped-types:"); |
277 | 0 | return extract_field(body, accept_wrapped_types, field); |
278 | 0 | } |
279 | | |
280 | | int extract_max_size(str *body, str *max_size) |
281 | 0 | { |
282 | 0 | static const str field = str_init("a=max-size:"); |
283 | 0 | return extract_field(body, max_size, field); |
284 | 0 | } |
285 | | |
286 | | int extract_path(str *body, str *path) |
287 | 0 | { |
288 | 0 | static const str field = str_init("a=path:"); |
289 | 0 | return extract_field(body, path, field); |
290 | 0 | } |
291 | | |
292 | | int extract_rtcp(str *body, str *rtcp) |
293 | 0 | { |
294 | 0 | static const str field = str_init("a=rtcp:"); |
295 | 0 | return extract_field(body, rtcp, field); |
296 | 0 | } |
297 | | |
298 | | int extract_sendrecv_mode(str *body, str *sendrecv_mode, int *is_on_hold) |
299 | 0 | { |
300 | 0 | char *cp1; |
301 | |
|
302 | 0 | if (body->len < 10) |
303 | 0 | return -1; |
304 | | |
305 | 0 | cp1 = body->s; |
306 | 0 | if ( !( (strncasecmp(cp1, "a=sendrecv", 10) == 0) || |
307 | 0 | (strncasecmp(cp1, "a=recvonly", 10) == 0))) { |
308 | 0 | if ( !( (strncasecmp(cp1, "a=inactive", 10) == 0) || |
309 | 0 | (strncasecmp(cp1, "a=sendonly", 10) == 0) )) { |
310 | 0 | return -1; |
311 | 0 | } else { |
312 | 0 | *is_on_hold = RFC3264_HOLD; |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | 0 | sendrecv_mode->s = body->s + 2; /* skip `a=' */ |
317 | 0 | sendrecv_mode->len = 8; /* we know the length and therefore we don't need to overkill */ |
318 | | /* |
319 | | sendrecv_mode->len = eat_line(sendrecv_mode->s, body->s + body->len - |
320 | | sendrecv_mode->s) - sendrecv_mode->s; |
321 | | trim_len(sendrecv_mode->len, sendrecv_mode->s, *sendrecv_mode); |
322 | | */ |
323 | |
|
324 | 0 | return 0; |
325 | 0 | } |
326 | | |
327 | | int extract_bwidth(str *body, str *bwtype, str *bwwitdth) |
328 | 0 | { |
329 | 0 | char *cp, *cp1; |
330 | 0 | int len; |
331 | |
|
332 | 0 | cp1 = NULL; |
333 | 0 | for (cp = body->s; (len = body->s + body->len - cp) > 0;) { |
334 | 0 | cp1 = (char*)l_memmem(cp, "b=", len, 2); |
335 | 0 | if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') |
336 | 0 | break; |
337 | 0 | cp = cp1 + 2; |
338 | 0 | } |
339 | 0 | if (cp1 == NULL) |
340 | 0 | return -1; |
341 | | |
342 | 0 | bwtype->s = cp1 + 2; |
343 | 0 | bwtype->len = eat_line(bwtype->s, body->s + body->len - bwtype->s) - bwtype->s; |
344 | 0 | trim_len(bwtype->len, bwtype->s, *bwtype); |
345 | |
|
346 | 0 | cp = bwtype->s; |
347 | 0 | len = bwtype->len; |
348 | 0 | cp1 = (char*)l_memmem(cp, ":", len, 1); |
349 | 0 | len -= cp1 - cp; |
350 | 0 | if (len <= 0) { |
351 | 0 | LM_ERR("invalid encoding in `b=%.*s'\n", bwtype->len, bwtype->s); |
352 | 0 | return -1; |
353 | 0 | } |
354 | 0 | bwtype->len = cp1 - cp; |
355 | | |
356 | | /* skip ':' */ |
357 | 0 | bwwitdth->s = cp1 + 1; |
358 | 0 | bwwitdth->len = len - 1; |
359 | |
|
360 | 0 | return 0; |
361 | 0 | } |
362 | | |
363 | | int extract_mediaip(str *body, str *mediaip, int *pf, char *line) |
364 | 0 | { |
365 | 0 | char *cp, *cp1; |
366 | 0 | int len, nextisip; |
367 | |
|
368 | 0 | cp1 = NULL; |
369 | 0 | for (cp = body->s; (len = body->s + body->len - cp) > 0;) { |
370 | 0 | cp1 = (char*)l_memmem(cp, line, len, 2); |
371 | 0 | if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') |
372 | 0 | break; |
373 | 0 | cp = cp1 + 2; |
374 | 0 | } |
375 | 0 | if (cp1 == NULL) |
376 | 0 | return -1; |
377 | | |
378 | 0 | mediaip->s = cp1 + 2; |
379 | 0 | mediaip->len = eat_line(mediaip->s, body->s + body->len - mediaip->s) - mediaip->s; |
380 | 0 | trim_len(mediaip->len, mediaip->s, *mediaip); |
381 | |
|
382 | 0 | nextisip = 0; |
383 | 0 | for (cp = mediaip->s; cp < mediaip->s + mediaip->len;) { |
384 | 0 | len = eat_token_end(cp, mediaip->s + mediaip->len) - cp; |
385 | 0 | if (nextisip == 1) { |
386 | 0 | mediaip->s = cp; |
387 | 0 | mediaip->len = len; |
388 | 0 | nextisip++; |
389 | 0 | break; |
390 | 0 | } |
391 | 0 | if (len == 3 && memcmp(cp, "IP", 2) == 0) { |
392 | 0 | switch (cp[2]) { |
393 | 0 | case '4': |
394 | 0 | nextisip = 1; |
395 | 0 | *pf = AF_INET; |
396 | 0 | break; |
397 | | |
398 | 0 | case '6': |
399 | 0 | nextisip = 1; |
400 | 0 | *pf = AF_INET6; |
401 | 0 | break; |
402 | | |
403 | 0 | default: |
404 | 0 | break; |
405 | 0 | } |
406 | 0 | } |
407 | | /* consume all spaces starting from the second char after the token |
408 | | First char after the token is the char that stoped the token |
409 | | parsing, so it is space or \r / \n, so we simply skip it */ |
410 | 0 | cp = eat_space_end(cp + len + 1, mediaip->s + mediaip->len); |
411 | 0 | } |
412 | 0 | if (nextisip != 2 || mediaip->len == 0) { |
413 | 0 | LM_ERR("no `IP[4|6]' in `%s' field\n",line); |
414 | 0 | return -1; |
415 | 0 | } |
416 | 0 | return 1; |
417 | 0 | } |
418 | | |
419 | | int extract_media_attr(str *body, str *mediamedia, str *mediaport, str *mediatransport, str *mediapayload, int *is_rtp) |
420 | 0 | { |
421 | 0 | char *cp, *cp1; |
422 | 0 | int len, i; |
423 | |
|
424 | 0 | cp1 = NULL; |
425 | 0 | for (cp = body->s; (len = body->s + body->len - cp) > 0;) { |
426 | 0 | cp1 = (char*)l_memmem(cp, "m=", len, 2); |
427 | 0 | if (cp1 == NULL || cp1[-1] == '\n' || cp1[-1] == '\r') |
428 | 0 | break; |
429 | 0 | cp = cp1 + 2; |
430 | 0 | } |
431 | 0 | if (cp1 == NULL) { |
432 | 0 | LM_ERR("no `m=' in SDP\n"); |
433 | 0 | return -1; |
434 | 0 | } |
435 | 0 | mediaport->s = cp1 + 2; /* skip `m=' */ |
436 | 0 | mediaport->len = eat_line(mediaport->s, body->s + body->len - |
437 | 0 | mediaport->s) - mediaport->s; |
438 | 0 | trim_len(mediaport->len, mediaport->s, *mediaport); |
439 | |
|
440 | 0 | mediapayload->len = mediaport->len; |
441 | 0 | mediamedia->s = mediaport->s; |
442 | | |
443 | | |
444 | | /* Skip media supertype and spaces after it */ |
445 | 0 | cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); |
446 | 0 | mediaport->len -= cp - mediaport->s; |
447 | 0 | mediamedia->len = mediapayload->len - mediaport->len; |
448 | 0 | if (mediaport->len <= 0 || cp == mediaport->s) { |
449 | 0 | LM_ERR("no port in `m='\n"); |
450 | 0 | return -1; |
451 | 0 | } |
452 | 0 | mediaport->s = cp; |
453 | |
|
454 | 0 | cp = eat_space_end(mediaport->s, mediaport->s + mediaport->len); |
455 | 0 | mediaport->len -= cp - mediaport->s; |
456 | 0 | if (mediaport->len <= 0 || cp == mediaport->s) { |
457 | 0 | LM_ERR("no port in `m='\n"); |
458 | 0 | return -1; |
459 | 0 | } |
460 | | |
461 | | /* Extract port */ |
462 | 0 | mediaport->s = cp; |
463 | 0 | cp = eat_token_end(mediaport->s, mediaport->s + mediaport->len); |
464 | 0 | mediatransport->len = mediaport->len - (cp - mediaport->s); |
465 | | /* coverity[copy_paste_error] false positive CID #40557 */ |
466 | 0 | if (mediatransport->len <= 0 || cp == mediaport->s) { |
467 | 0 | LM_ERR("no port in `m='\n"); |
468 | 0 | return -1; |
469 | 0 | } |
470 | 0 | mediatransport->s = cp; |
471 | 0 | mediaport->len = cp - mediaport->s; |
472 | | |
473 | | /* Skip spaces after port */ |
474 | 0 | cp = eat_space_end(mediatransport->s, mediatransport->s + mediatransport->len); |
475 | 0 | mediatransport->len -= cp - mediatransport->s; |
476 | 0 | if (mediatransport->len <= 0 || cp == mediatransport->s) { |
477 | 0 | LM_ERR("no protocol type in `m='\n"); |
478 | 0 | return -1; |
479 | 0 | } |
480 | | /* Extract protocol type */ |
481 | 0 | mediatransport->s = cp; |
482 | 0 | cp = eat_token_end(mediatransport->s, mediatransport->s + mediatransport->len); |
483 | 0 | if (cp == mediatransport->s) { |
484 | 0 | LM_ERR("no protocol type in `m='\n"); |
485 | 0 | return -1; |
486 | 0 | } |
487 | 0 | mediatransport->len = cp - mediatransport->s; |
488 | |
|
489 | 0 | mediapayload->s = mediatransport->s + mediatransport->len; |
490 | 0 | mediapayload->len -= mediapayload->s - mediamedia->s; |
491 | 0 | cp = eat_space_end(mediapayload->s, mediapayload->s + mediapayload->len); |
492 | 0 | mediapayload->len -= cp - mediapayload->s; |
493 | 0 | mediapayload->s = cp; |
494 | |
|
495 | 0 | for (i = 0; sup_ptypes[i].s != NULL; i++) |
496 | 0 | if (mediatransport->len == sup_ptypes[i].len && |
497 | 0 | strncasecmp(mediatransport->s, sup_ptypes[i].s, mediatransport->len) == 0) { |
498 | 0 | *is_rtp = sup_ptypes[i].is_rtp; |
499 | 0 | return 0; |
500 | 0 | } |
501 | | /* Unproxyable protocol type. Generally it isn't error. */ |
502 | 0 | return 0; |
503 | 0 | } |
504 | | |
505 | | |
506 | | /* |
507 | | * Auxiliary for some functions. |
508 | | * Returns pointer to first character of found line, or NULL if no such line. |
509 | | */ |
510 | | |
511 | | char *find_sdp_line(char* p, char* plimit, char linechar) |
512 | 0 | { |
513 | 0 | static char linehead[3] = "x="; |
514 | 0 | char *cp, *cp1; |
515 | 0 | linehead[0] = linechar; |
516 | | /* Iterate through body */ |
517 | 0 | cp = p; |
518 | 0 | for (;;) { |
519 | 0 | if (cp >= plimit) |
520 | 0 | return NULL; |
521 | 0 | cp1 = l_memmem(cp, linehead, plimit-cp, 2); |
522 | 0 | if (cp1 == NULL) |
523 | 0 | return NULL; |
524 | | /* |
525 | | * As it is body, we assume it has previous line and we can |
526 | | * lookup previous character. |
527 | | */ |
528 | 0 | if (cp1[-1] == '\n' || cp1[-1] == '\r') |
529 | 0 | return cp1; |
530 | | /* |
531 | | * Having such data, but not at line beginning. |
532 | | * Skip them and reiterate. l_memmem() will find next |
533 | | * occurence. |
534 | | */ |
535 | 0 | if (plimit - cp1 < 2) |
536 | 0 | return NULL; |
537 | 0 | cp = cp1 + 2; |
538 | 0 | } |
539 | 0 | } |
540 | | |
541 | | |
542 | | |
543 | | /* |
544 | | * Auxiliary for some functions. |
545 | | * Returns pointer to first character of found line, or NULL if no such line. |
546 | | */ |
547 | | |
548 | | char *find_sdp_line_complex(char* p, char* plimit, char * name) |
549 | 0 | { |
550 | 0 | char *cp, *cp1; |
551 | 0 | int len = strlen(name); |
552 | | |
553 | | /* Iterate through body */ |
554 | 0 | cp = p; |
555 | 0 | for (;;) { |
556 | 0 | if (cp >= plimit) |
557 | 0 | return NULL; |
558 | 0 | cp1 = l_memmem(cp, name, plimit-cp, len); |
559 | 0 | if (cp1 == NULL) |
560 | 0 | return NULL; |
561 | | /* |
562 | | * As it is body, we assume it has previous line and we can |
563 | | * lookup previous character. |
564 | | */ |
565 | 0 | if (cp1[-1] == '\n' || cp1[-1] == '\r') |
566 | 0 | return cp1; |
567 | | /* |
568 | | * Having such data, but not at line beginning. |
569 | | * Skip them and reiterate. l_memmem() will find next |
570 | | * occurence. |
571 | | */ |
572 | 0 | if (plimit - cp1 < 2) |
573 | 0 | return NULL; |
574 | 0 | cp = cp1 + 2; |
575 | 0 | } |
576 | 0 | } |
577 | | |
578 | | |
579 | | /* This function assumes p points to a line of requested type. */ |
580 | | char * find_next_sdp_line(char* p, char* plimit, char linechar, char* defptr) |
581 | 0 | { |
582 | 0 | char *t; |
583 | 0 | if (p >= plimit || plimit - p < 3) |
584 | 0 | return defptr; |
585 | 0 | t = find_sdp_line(p + 2, plimit, linechar); |
586 | 0 | return t ? t : defptr; |
587 | 0 | } |
588 | | |
589 | | |
590 | | /* returns pointer to next header line, and fill hdr_f ; |
591 | | * if at end of header returns pointer to the last crlf (always buf)*/ |
592 | | char* get_sdp_hdr_field(char* buf, char* end, struct hdr_field* hdr) |
593 | 0 | { |
594 | |
|
595 | 0 | char* tmp; |
596 | 0 | char *match; |
597 | |
|
598 | 0 | if ((*buf)=='\n' || (*buf)=='\r'){ |
599 | | /* double crlf or lflf or crcr */ |
600 | 0 | hdr->type=HDR_EOH_T; |
601 | 0 | return buf; |
602 | 0 | } |
603 | | |
604 | 0 | tmp=parse_hname2(buf, end, hdr); |
605 | 0 | if (hdr->type==HDR_ERROR_T){ |
606 | 0 | LM_ERR("bad header\n"); |
607 | 0 | goto error; |
608 | 0 | } |
609 | | |
610 | | /* eliminate leading whitespace */ |
611 | 0 | tmp=eat_lws_end(tmp, end); |
612 | 0 | if (tmp>=end) { |
613 | 0 | LM_ERR("hf empty\n"); |
614 | 0 | goto error; |
615 | 0 | } |
616 | | |
617 | | /* if header-field well-known, parse it, find its end otherwise ; |
618 | | * after leaving the hdr->type switch, tmp should be set to the |
619 | | * next header field |
620 | | */ |
621 | 0 | switch(hdr->type){ |
622 | 0 | case HDR_CONTENTTYPE_T: |
623 | 0 | case HDR_CONTENTDISPOSITION_T: |
624 | | /* just skip over it */ |
625 | 0 | hdr->body.s=tmp; |
626 | | /* find end of header */ |
627 | | /* find lf */ |
628 | 0 | do{ |
629 | 0 | match=q_memchr(tmp, '\n', end-tmp); |
630 | 0 | if (match){ |
631 | 0 | match++; |
632 | 0 | }else { |
633 | 0 | LM_ERR("bad body for <%s>(%d)\n", hdr->name.s, hdr->type); |
634 | 0 | tmp=end; |
635 | 0 | goto error; |
636 | 0 | } |
637 | 0 | tmp=match; |
638 | 0 | }while( match<end &&( (*match==' ')||(*match=='\t') ) ); |
639 | 0 | tmp=match; |
640 | 0 | hdr->body.len=match-hdr->body.s; |
641 | 0 | break; |
642 | 0 | default: |
643 | 0 | LM_CRIT("unknown header type %d\n", hdr->type); |
644 | 0 | goto error; |
645 | 0 | } |
646 | | /* jku: if \r covered by current length, shrink it */ |
647 | 0 | trim_r( hdr->body ); |
648 | 0 | hdr->len=tmp-hdr->name.s; |
649 | 0 | return tmp; |
650 | 0 | error: |
651 | 0 | LM_DBG("error exit\n"); |
652 | 0 | hdr->type=HDR_ERROR_T; |
653 | 0 | hdr->len=tmp-hdr->name.s; |
654 | 0 | return tmp; |
655 | 0 | } |
656 | | |