Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include <errno.h>
6 :
7 : #include "sdp_os_defs.h"
8 : #include "sdp.h"
9 : #include "sdp_private.h"
10 :
11 : #include "CSFLog.h"
12 : #include "prprf.h"
13 :
14 : static const char *logTag = "sdp_token";
15 :
16 : #define MCAST_STRING_LEN 4
17 :
18 :
19 0 : sdp_result_e sdp_parse_version (sdp_t *sdp_p, uint16_t level, const char *ptr)
20 : {
21 0 : sdp_result_e result = SDP_FAILURE;
22 :
23 0 : sdp_p->version = (uint16_t)sdp_getnextnumtok(ptr, &ptr, " \t", &result);
24 0 : if ((result != SDP_SUCCESS) || (sdp_p->version != SDP_CURRENT_VERSION)) {
25 0 : sdp_parse_error(sdp_p,
26 : "%s Invalid version (%u) found, parse failed.",
27 0 : sdp_p->debug_str, (unsigned)sdp_p->version);
28 0 : sdp_p->conf_p->num_invalid_param++;
29 0 : return (SDP_INVALID_PARAMETER);
30 : }
31 :
32 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
33 0 : SDP_PRINT("%s Parse version line successful, version %u",
34 : sdp_p->debug_str, (unsigned)sdp_p->version);
35 : }
36 0 : return (SDP_SUCCESS);
37 : }
38 :
39 0 : sdp_result_e sdp_build_version (sdp_t *sdp_p, uint16_t level, flex_string *fs)
40 : {
41 0 : if (sdp_p->version == SDP_INVALID_VALUE) {
42 0 : if (sdp_p->conf_p->version_reqd == TRUE) {
43 0 : CSFLogError(logTag, "%s Invalid version for v= line, "
44 : "build failed.", sdp_p->debug_str);
45 0 : sdp_p->conf_p->num_invalid_param++;
46 0 : return (SDP_INVALID_PARAMETER);
47 : } else {
48 : /* v= line is not required. */
49 0 : return (SDP_SUCCESS);
50 : }
51 : }
52 :
53 0 : flex_string_sprintf(fs, "v=%u\r\n", (unsigned)sdp_p->version);
54 :
55 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
56 0 : SDP_PRINT("%s Built v= version line", sdp_p->debug_str);
57 : }
58 0 : return (SDP_SUCCESS);
59 : }
60 :
61 0 : static sdp_result_e sdp_verify_unsigned(const char *ptr, uint64_t max_value)
62 : {
63 : uint64_t numeric_value;
64 : /* Checking for only numbers since PR_sscanf will ignore trailing
65 : characters */
66 0 : size_t end = strspn(ptr, "0123456789");
67 :
68 0 : if (ptr[end] != '\0')
69 0 : return SDP_INVALID_PARAMETER;
70 :
71 0 : if (PR_sscanf(ptr, "%llu", &numeric_value) != 1)
72 0 : return SDP_INVALID_PARAMETER;
73 :
74 0 : if (numeric_value > max_value)
75 0 : return SDP_INVALID_PARAMETER;
76 :
77 0 : return SDP_SUCCESS;
78 : }
79 :
80 0 : sdp_result_e sdp_parse_owner (sdp_t *sdp_p, uint16_t level, const char *ptr)
81 : {
82 : int i;
83 : sdp_result_e result;
84 : char tmp[SDP_MAX_STRING_LEN];
85 : /* The spec says this:
86 :
87 : The numeric value of the session id
88 : and version in the o line MUST be representable with a 64 bit signed
89 : integer. The initial value of the version MUST be less than
90 : (2**62)-1, to avoid rollovers.
91 : */
92 0 : const uint64_t max_value_sessid = ((((uint64_t) 1) << 63) - 1);
93 : /* Do not check that this is 2^62 - 1; that's just the limit on
94 : * the initial version, not every version number. */
95 0 : const uint64_t max_value_version = ((((uint64_t) 1) << 63) - 1);
96 :
97 0 : if (sdp_p->owner_name[0] != '\0') {
98 0 : sdp_p->conf_p->num_invalid_token_order++;
99 0 : sdp_parse_error(sdp_p,
100 : "%s Warning: More than one o= line specified.",
101 0 : sdp_p->debug_str);
102 : }
103 :
104 : /* Find the owner name. */
105 0 : ptr = sdp_getnextstrtok(ptr, sdp_p->owner_name, sizeof(sdp_p->owner_name), " \t", &result);
106 0 : if (result != SDP_SUCCESS) {
107 0 : sdp_parse_error(sdp_p,
108 : "%s No owner name specified for o=.",
109 0 : sdp_p->debug_str);
110 0 : sdp_p->conf_p->num_invalid_param++;
111 0 : return (SDP_INVALID_PARAMETER);
112 : }
113 :
114 : /* Find the owner session id. This is a numeric field but is
115 : * stored as a string since it may be 64 bit.
116 : */
117 0 : ptr = sdp_getnextstrtok(ptr, sdp_p->owner_sessid, sizeof(sdp_p->owner_sessid), " \t", &result);
118 0 : if (result == SDP_SUCCESS) {
119 : /* Make sure the sessid is numeric, even though we store it as
120 : * a string.
121 : */
122 0 : result = sdp_verify_unsigned(sdp_p->owner_sessid, max_value_sessid);
123 : }
124 0 : if (result != SDP_SUCCESS) {
125 0 : sdp_parse_error(sdp_p,
126 : "%s Invalid owner session id specified for o=.",
127 0 : sdp_p->debug_str);
128 0 : sdp_p->conf_p->num_invalid_param++;
129 0 : return (SDP_INVALID_PARAMETER);
130 : }
131 :
132 : /* Find the owner version. */
133 0 : ptr = sdp_getnextstrtok(ptr, sdp_p->owner_version, sizeof(sdp_p->owner_version), " \t", &result);
134 0 : if (result == SDP_SUCCESS) {
135 : /* Make sure the version is numeric, even though we store it as
136 : * a string.
137 : */
138 0 : result = sdp_verify_unsigned(sdp_p->owner_version, max_value_version);
139 : }
140 0 : if (result != SDP_SUCCESS) {
141 0 : sdp_parse_error(sdp_p,
142 : "%s Invalid owner version specified for o=.",
143 0 : sdp_p->debug_str);
144 0 : sdp_p->conf_p->num_invalid_param++;
145 0 : return (SDP_INVALID_PARAMETER);
146 : }
147 :
148 : /* Find the owner network type. */
149 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
150 0 : if (result != SDP_SUCCESS) {
151 0 : sdp_parse_error(sdp_p,
152 : "%s No owner network type specified for o=.",
153 0 : sdp_p->debug_str);
154 0 : sdp_p->conf_p->num_invalid_param++;
155 0 : return (SDP_INVALID_PARAMETER);
156 : }
157 0 : sdp_p->owner_network_type = SDP_NT_UNSUPPORTED;
158 0 : for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
159 0 : if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
160 0 : sdp_nettype[i].strlen) == 0) {
161 0 : if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
162 0 : sdp_p->owner_network_type = (sdp_nettype_e)i;
163 : }
164 : }
165 : }
166 0 : if (sdp_p->owner_network_type == SDP_NT_UNSUPPORTED) {
167 0 : sdp_parse_error(sdp_p,
168 : "%s Owner network type unsupported (%s)",
169 0 : sdp_p->debug_str, tmp);
170 0 : sdp_p->conf_p->num_invalid_param++;
171 0 : return (SDP_INVALID_PARAMETER);
172 : }
173 :
174 : /* Find the owner address type. */
175 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
176 0 : if (result != SDP_SUCCESS) {
177 0 : sdp_parse_error(sdp_p,
178 : "%s No owner address type specified for o=.",
179 0 : sdp_p->debug_str);
180 0 : sdp_p->conf_p->num_invalid_param++;
181 0 : return (SDP_INVALID_PARAMETER);
182 : }
183 0 : sdp_p->owner_addr_type = SDP_AT_UNSUPPORTED;
184 0 : for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
185 0 : if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
186 0 : sdp_addrtype[i].strlen) == 0) {
187 0 : if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
188 0 : sdp_p->owner_addr_type = (sdp_addrtype_e)i;
189 : }
190 : }
191 : }
192 0 : if ((sdp_p->owner_addr_type == SDP_AT_UNSUPPORTED) &&
193 0 : (sdp_p->owner_network_type != SDP_NT_ATM)) {
194 0 : sdp_parse_error(sdp_p,
195 : "%s Owner address type unsupported (%s)",
196 0 : sdp_p->debug_str, tmp);
197 0 : sdp_p->conf_p->num_invalid_param++;
198 0 : return (SDP_INVALID_PARAMETER);
199 : }
200 :
201 : /* Find the owner address. */
202 0 : ptr = sdp_getnextstrtok(ptr, sdp_p->owner_addr, sizeof(sdp_p->owner_addr), " \t", &result);
203 0 : if (result != SDP_SUCCESS) {
204 0 : sdp_parse_error(sdp_p,
205 0 : "%s No owner address specified.", sdp_p->debug_str);
206 0 : sdp_p->conf_p->num_invalid_param++;
207 0 : return (SDP_INVALID_PARAMETER);
208 : }
209 :
210 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
211 0 : SDP_PRINT("%s Parse owner: name %s, session id %s, version %s",
212 : sdp_p->debug_str, sdp_p->owner_name, sdp_p->owner_sessid,
213 : sdp_p->owner_version);
214 0 : SDP_PRINT("%s network %s, address type %s, "
215 : "address %s", sdp_p->debug_str,
216 : sdp_get_network_name(sdp_p->owner_network_type),
217 : sdp_get_address_name(sdp_p->owner_addr_type),
218 : sdp_p->owner_addr);
219 : }
220 0 : return (SDP_SUCCESS);
221 : }
222 :
223 0 : sdp_result_e sdp_build_owner (sdp_t *sdp_p, uint16_t level, flex_string *fs)
224 : {
225 0 : if ((sdp_p->owner_name[0] == '\0') ||
226 0 : (sdp_p->owner_network_type >= SDP_MAX_NETWORK_TYPES) ||
227 0 : (sdp_p->owner_addr_type >= SDP_MAX_ADDR_TYPES) ||
228 0 : (sdp_p->owner_addr[0] == '\0')) {
229 :
230 0 : if((sdp_p->owner_network_type == SDP_NT_ATM) &&
231 0 : (sdp_p->owner_addr_type == SDP_AT_INVALID)) {
232 0 : flex_string_sprintf(fs, "o=%s %s %s %s - -\r\n",
233 0 : sdp_p->owner_name, sdp_p->owner_sessid,
234 0 : sdp_p->owner_version,
235 : sdp_get_network_name(sdp_p->owner_network_type));
236 : }
237 :
238 0 : if (sdp_p->conf_p->owner_reqd == TRUE) {
239 0 : CSFLogError(logTag, "%s Invalid params for o= owner line, "
240 : "build failed.", sdp_p->debug_str);
241 0 : sdp_p->conf_p->num_invalid_param++;
242 0 : return (SDP_INVALID_PARAMETER);
243 : } else {
244 : /* o= line is not required. */
245 0 : return (SDP_SUCCESS);
246 : }
247 : }
248 :
249 0 : flex_string_sprintf(fs, "o=%s %s %s %s %s %s\r\n",
250 0 : sdp_p->owner_name, sdp_p->owner_sessid,
251 0 : sdp_p->owner_version,
252 : sdp_get_network_name(sdp_p->owner_network_type),
253 : sdp_get_address_name(sdp_p->owner_addr_type),
254 0 : sdp_p->owner_addr);
255 :
256 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
257 0 : SDP_PRINT("%s Built o= owner line", sdp_p->debug_str);
258 : }
259 0 : return (SDP_SUCCESS);
260 : }
261 :
262 0 : sdp_result_e sdp_parse_sessname (sdp_t *sdp_p, uint16_t level, const char *ptr)
263 : {
264 : int str_len;
265 : char *endptr;
266 :
267 0 : if (sdp_p->sessname[0] != '\0') {
268 0 : sdp_p->conf_p->num_invalid_token_order++;
269 0 : sdp_parse_error(sdp_p,
270 : "%s Warning: More than one s= line specified.",
271 0 : sdp_p->debug_str);
272 : }
273 :
274 0 : endptr = sdp_findchar(ptr, "\r\n");
275 0 : if (ptr == endptr) {
276 0 : sdp_parse_error(sdp_p,
277 : "%s Warning: No session name specified.",
278 0 : sdp_p->debug_str);
279 : }
280 0 : str_len = MIN(endptr - ptr, SDP_MAX_STRING_LEN);
281 0 : sstrncpy(sdp_p->sessname, ptr, str_len+1);
282 :
283 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
284 0 : SDP_PRINT("%s Parse session name, %s",
285 : sdp_p->debug_str, sdp_p->sessname);
286 : }
287 0 : return (SDP_SUCCESS);
288 : }
289 :
290 0 : sdp_result_e sdp_build_sessname (sdp_t *sdp_p, uint16_t level, flex_string *fs)
291 : {
292 0 : if (sdp_p->sessname[0] == '\0') {
293 0 : if (sdp_p->conf_p->session_name_reqd == TRUE) {
294 0 : CSFLogError(logTag, "%s No param defined for s= session name line, "
295 : "build failed.", sdp_p->debug_str);
296 0 : sdp_p->conf_p->num_invalid_param++;
297 0 : return (SDP_INVALID_PARAMETER);
298 : } else {
299 : /* s= line is not required. */
300 0 : return (SDP_SUCCESS);
301 : }
302 : }
303 :
304 0 : flex_string_sprintf(fs, "s=%s\r\n", sdp_p->sessname);
305 :
306 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
307 0 : SDP_PRINT("%s Built s= session name line", sdp_p->debug_str);
308 : }
309 0 : return (SDP_SUCCESS);
310 : }
311 :
312 : /* We don't want to store the session info, but we do want to validate
313 : * that at most one i= line exists at each level and if the line exists
314 : * there should be a parameter.
315 : */
316 0 : sdp_result_e sdp_parse_sessinfo (sdp_t *sdp_p, uint16_t level, const char *ptr)
317 : {
318 : char *endptr;
319 : sdp_mca_t *mca_p;
320 :
321 0 : if (level == SDP_SESSION_LEVEL) {
322 0 : if (sdp_p->sessinfo_found == TRUE) {
323 0 : sdp_p->conf_p->num_invalid_token_order++;
324 0 : sdp_parse_error(sdp_p,
325 : "%s Warning: More than one i= line specified.",
326 0 : sdp_p->debug_str);
327 : }
328 0 : sdp_p->sessinfo_found = TRUE;
329 : } else {
330 0 : mca_p = sdp_find_media_level(sdp_p, level);
331 0 : if (mca_p == NULL) {
332 0 : return (SDP_FAILURE);
333 : }
334 0 : if (mca_p->sessinfo_found == TRUE) {
335 0 : sdp_p->conf_p->num_invalid_token_order++;
336 0 : sdp_parse_error(sdp_p,
337 : "%s Warning: More than one i= line specified"
338 0 : " for media line %u.", sdp_p->debug_str, (unsigned)level);
339 : }
340 0 : mca_p->sessinfo_found = TRUE;
341 : }
342 :
343 0 : endptr = sdp_findchar(ptr, "\n");
344 0 : if (ptr == endptr) {
345 0 : sdp_parse_error(sdp_p,
346 : "%s Warning: No session info specified.",
347 0 : sdp_p->debug_str);
348 : }
349 :
350 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
351 0 : SDP_PRINT("%s Parsed session info line.", sdp_p->debug_str);
352 : }
353 0 : return (SDP_SUCCESS);
354 : }
355 :
356 0 : sdp_result_e sdp_build_sessinfo (sdp_t *sdp_p, uint16_t level, flex_string *fs)
357 : {
358 : /* Build session info line not supported. */
359 0 : return (SDP_SUCCESS);
360 : }
361 :
362 0 : sdp_result_e sdp_parse_uri (sdp_t *sdp_p, uint16_t level, const char *ptr)
363 : {
364 : char *endptr;
365 :
366 0 : if (sdp_p->uri_found == TRUE) {
367 0 : sdp_p->conf_p->num_invalid_token_order++;
368 0 : sdp_parse_error(sdp_p,
369 : "%s Warning: More than one u= line specified.",
370 0 : sdp_p->debug_str);
371 : }
372 0 : sdp_p->uri_found = TRUE;
373 :
374 0 : endptr = sdp_findchar(ptr, "\n");
375 0 : if (ptr == endptr) {
376 0 : sdp_parse_error(sdp_p,
377 0 : "%s Warning: No URI info specified.", sdp_p->debug_str);
378 : }
379 :
380 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
381 0 : SDP_PRINT("%s Parsed URI line.", sdp_p->debug_str);
382 : }
383 0 : return (SDP_SUCCESS);
384 : }
385 :
386 0 : sdp_result_e sdp_build_uri (sdp_t *sdp_p, uint16_t level, flex_string *fs)
387 : {
388 : /* Build URI line not supported. */
389 0 : return (SDP_SUCCESS);
390 : }
391 :
392 0 : sdp_result_e sdp_parse_email (sdp_t *sdp_p, uint16_t level, const char *ptr)
393 : {
394 : char *endptr;
395 :
396 0 : endptr = sdp_findchar(ptr, "\n");
397 0 : if (ptr == endptr) {
398 0 : sdp_parse_error(sdp_p,
399 0 : "%s Warning: No email info specified.", sdp_p->debug_str);
400 : }
401 :
402 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
403 0 : SDP_PRINT("%s Parse email line", sdp_p->debug_str);
404 : }
405 0 : return (SDP_SUCCESS);
406 : }
407 :
408 0 : sdp_result_e sdp_build_email (sdp_t *sdp_p, uint16_t level, flex_string *fs)
409 : {
410 : /* Build email line not supported. */
411 0 : return (SDP_SUCCESS);
412 : }
413 :
414 0 : sdp_result_e sdp_parse_phonenum (sdp_t *sdp_p, uint16_t level, const char *ptr)
415 : {
416 : char *endptr;
417 :
418 0 : endptr = sdp_findchar(ptr, "\n");
419 0 : if (ptr == endptr) {
420 0 : sdp_parse_error(sdp_p,
421 : "%s Warning: No phone number info specified.",
422 0 : sdp_p->debug_str);
423 : }
424 :
425 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
426 0 : SDP_PRINT("%s Parse phone number line", sdp_p->debug_str);
427 : }
428 0 : return (SDP_SUCCESS);
429 : }
430 :
431 0 : sdp_result_e sdp_build_phonenum (sdp_t *sdp_p, uint16_t level, flex_string *fs)
432 : {
433 : /* Build phone number line not supported. */
434 0 : return (SDP_SUCCESS);
435 : }
436 :
437 0 : sdp_result_e sdp_parse_connection (sdp_t *sdp_p, uint16_t level, const char *ptr)
438 : {
439 : int i;
440 : const char *slash_ptr;
441 : sdp_result_e result;
442 : sdp_conn_t *conn_p;
443 : sdp_mca_t *mca_p;
444 : char tmp[SDP_MAX_STRING_LEN];
445 : char mcast_str[MCAST_STRING_LEN];
446 : int mcast_bits;
447 : unsigned long strtoul_result;
448 : char *strtoul_end;
449 :
450 0 : if (level == SDP_SESSION_LEVEL) {
451 0 : conn_p = &(sdp_p->default_conn);
452 : } else {
453 0 : mca_p = sdp_find_media_level(sdp_p, level);
454 0 : if (mca_p == NULL) {
455 0 : return (SDP_FAILURE);
456 : }
457 0 : conn_p = &(mca_p->conn);
458 : }
459 :
460 : /* See if the c= line is already defined at this level. We don't
461 : * currently support multihoming and so we only support one c= at
462 : * each level.
463 : */
464 0 : if (conn_p->nettype != SDP_NT_INVALID) {
465 0 : sdp_p->conf_p->num_invalid_token_order++;
466 0 : sdp_parse_error(sdp_p,
467 : "%s c= line specified twice at same level, "
468 0 : "parse failed.", sdp_p->debug_str);
469 0 : return (SDP_INVALID_TOKEN_ORDERING);
470 : }
471 :
472 : /* Find the connection network type. */
473 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
474 0 : if (result != SDP_SUCCESS) {
475 0 : sdp_parse_error(sdp_p,
476 : "%s No connection network type specified for c=.",
477 0 : sdp_p->debug_str);
478 0 : sdp_p->conf_p->num_invalid_param++;
479 0 : return (SDP_INVALID_PARAMETER);
480 : }
481 0 : conn_p->nettype = SDP_NT_UNSUPPORTED;
482 0 : for (i=0; i < SDP_MAX_NETWORK_TYPES; i++) {
483 0 : if (cpr_strncasecmp(tmp, sdp_nettype[i].name,
484 0 : sdp_nettype[i].strlen) == 0) {
485 0 : if (sdp_p->conf_p->nettype_supported[i] == TRUE) {
486 0 : conn_p->nettype = (sdp_nettype_e)i;
487 : }
488 : }
489 : }
490 0 : if (conn_p->nettype == SDP_NT_UNSUPPORTED) {
491 0 : sdp_parse_error(sdp_p,
492 : "%s Warning: Connection network type unsupported "
493 0 : "(%s) for c=.", sdp_p->debug_str, tmp);
494 : }
495 :
496 : /* Find the connection address type. */
497 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
498 0 : if (result != SDP_SUCCESS) {
499 0 : if (conn_p->nettype == SDP_NT_ATM) {
500 : /* If the nettype is ATM, addr type and addr are not reqd */
501 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
502 0 : SDP_PRINT("%s Parse connection: network %s", sdp_p->debug_str,
503 : sdp_get_network_name(conn_p->nettype));
504 : }
505 0 : return (SDP_SUCCESS);
506 : } else {
507 0 : sdp_parse_error(sdp_p,
508 : "%s No connection address type specified for "
509 0 : "c=.", sdp_p->debug_str);
510 0 : sdp_p->conf_p->num_invalid_param++;
511 0 : return (SDP_INVALID_PARAMETER);
512 : }
513 : }
514 0 : conn_p->addrtype = SDP_AT_UNSUPPORTED;
515 0 : for (i=0; i < SDP_MAX_ADDR_TYPES; i++) {
516 0 : if (cpr_strncasecmp(tmp, sdp_addrtype[i].name,
517 0 : sdp_addrtype[i].strlen) == 0) {
518 0 : if (sdp_p->conf_p->addrtype_supported[i] == TRUE) {
519 0 : conn_p->addrtype = (sdp_addrtype_e)i;
520 : }
521 : }
522 : }
523 0 : if (conn_p->addrtype == SDP_AT_UNSUPPORTED) {
524 0 : sdp_parse_error(sdp_p,
525 : "%s Warning: Connection address type unsupported "
526 0 : "(%s) for c=.", sdp_p->debug_str, tmp);
527 : }
528 :
529 : /* Find the connection address. */
530 0 : ptr = sdp_getnextstrtok(ptr, conn_p->conn_addr, sizeof(conn_p->conn_addr), " \t", &result);
531 0 : if (result != SDP_SUCCESS) {
532 0 : sdp_parse_error(sdp_p,
533 : "%s No connection address specified for c=.",
534 0 : sdp_p->debug_str);
535 0 : sdp_p->conf_p->num_invalid_param++;
536 0 : return (SDP_INVALID_PARAMETER);
537 : }
538 : /* We currently only support addrs containing '/'s for EPN addrs.
539 : * For other addrs this would indicate multicast addrs. */
540 : /* Multicast host group addresses are defined to be the IP addresses
541 : * whose high-order four bits are 1110, giving an address range from
542 : * 224.0.0.0 through 239.255.255.255
543 : */
544 : /* multicast addr check */
545 0 : sstrncpy (mcast_str, conn_p->conn_addr, MCAST_STRING_LEN);
546 :
547 0 : if (conn_p->addrtype == SDP_AT_IP4) {
548 0 : errno = 0;
549 0 : strtoul_result = strtoul(mcast_str, &strtoul_end, 10);
550 :
551 0 : if (errno || mcast_str == strtoul_end || strtoul_result > 255) {
552 0 : sdp_parse_error(sdp_p,
553 : "%s Error parsing address %s for mcast.",
554 0 : sdp_p->debug_str, mcast_str);
555 0 : sdp_p->conf_p->num_invalid_param++;
556 0 : return SDP_INVALID_PARAMETER;
557 : }
558 :
559 :
560 0 : mcast_bits = (int) strtoul_result;
561 0 : if ((mcast_bits >= SDP_MIN_MCAST_ADDR_HI_BIT_VAL ) &&
562 : (mcast_bits <= SDP_MAX_MCAST_ADDR_HI_BIT_VAL)) {
563 0 : SDP_PRINT("%s Parsed to be a multicast address with mcast bits %d",
564 : sdp_p->debug_str, mcast_bits);
565 0 : conn_p->is_multicast = TRUE;
566 : }
567 : }
568 :
569 0 : if (conn_p->addrtype != SDP_AT_EPN) {
570 0 : slash_ptr = sdp_findchar(conn_p->conn_addr, "/");
571 0 : if (slash_ptr[0] != '\0') {
572 : /* this used to rely on the above busted multicast check */
573 0 : SDP_PRINT("%s An address with slash %s",
574 : sdp_p->debug_str, conn_p->conn_addr);
575 0 : conn_p->conn_addr[slash_ptr - conn_p->conn_addr] = '\0';
576 0 : slash_ptr++;
577 0 : slash_ptr = sdp_getnextstrtok(slash_ptr, tmp, sizeof(tmp),
578 : "/", &result);
579 0 : if (result != SDP_SUCCESS) {
580 0 : sdp_parse_error(sdp_p,
581 : "%s No ttl value specified for this multicast addr with a slash",
582 0 : sdp_p->debug_str);
583 0 : sdp_p->conf_p->num_invalid_param++;
584 0 : return (SDP_INVALID_PARAMETER);
585 : }
586 :
587 0 : errno = 0;
588 0 : strtoul_result = strtoul(tmp, &strtoul_end, 10);
589 :
590 0 : if (errno || tmp == strtoul_end || conn_p->ttl > SDP_MAX_TTL_VALUE) {
591 0 : sdp_parse_error(sdp_p,
592 : "%s Invalid TTL: Value must be in the range 0-255 ",
593 0 : sdp_p->debug_str);
594 0 : sdp_p->conf_p->num_invalid_param++;
595 0 : return (SDP_INVALID_PARAMETER);
596 : }
597 :
598 0 : conn_p->ttl = (int) strtoul_result;
599 :
600 : /* search for num of addresses */
601 : /*sa_ignore NO_NULL_CHK
602 : {ptr is valid since the pointer was checked earlier and the
603 : function would have exited if NULL.}*/
604 0 : slash_ptr = sdp_findchar(slash_ptr, "/");
605 0 : if (slash_ptr != NULL &&
606 0 : slash_ptr[0] != '\0') {
607 0 : SDP_PRINT("%s Found a num addr field for multicast addr %s ",
608 : sdp_p->debug_str,slash_ptr);
609 0 : slash_ptr++;
610 :
611 0 : errno = 0;
612 0 : strtoul_result = strtoul(slash_ptr, &strtoul_end, 10);
613 :
614 0 : if (errno || slash_ptr == strtoul_end || strtoul_result == 0) {
615 0 : sdp_parse_error(sdp_p,
616 : "%s Invalid Num of addresses: Value must be > 0 ",
617 0 : sdp_p->debug_str);
618 0 : sdp_p->conf_p->num_invalid_param++;
619 0 : return SDP_INVALID_PARAMETER;
620 : }
621 :
622 0 : conn_p->num_of_addresses = (int) strtoul_result;
623 : }
624 : }
625 : }
626 :
627 : /* See if the address is the choose param and if it's allowed. */
628 0 : if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_CONN_ADDR] == FALSE) &&
629 0 : (strcmp(conn_p->conn_addr, "$") == 0)) {
630 0 : sdp_parse_error(sdp_p,
631 : "%s Warning: Choose parameter for connection "
632 0 : "address specified but not allowed.", sdp_p->debug_str);
633 : }
634 :
635 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
636 0 : SDP_PRINT("%s Parse connection: network %s, address type %s, "
637 : "address %s ttl= %u num of addresses = %u",
638 : sdp_p->debug_str,
639 : sdp_get_network_name(conn_p->nettype),
640 : sdp_get_address_name(conn_p->addrtype),
641 : conn_p->conn_addr, (unsigned)conn_p->ttl, (unsigned)conn_p->num_of_addresses);
642 : }
643 0 : return (SDP_SUCCESS);
644 : }
645 :
646 0 : sdp_result_e sdp_build_connection (sdp_t *sdp_p, uint16_t level, flex_string *fs)
647 : {
648 : sdp_mca_t *mca_p;
649 : sdp_conn_t *conn_p;
650 :
651 0 : if (level == SDP_SESSION_LEVEL) {
652 0 : conn_p = &(sdp_p->default_conn);
653 : } else {
654 0 : mca_p = sdp_find_media_level(sdp_p, level);
655 0 : if (mca_p == NULL) {
656 0 : return (SDP_FAILURE);
657 : }
658 0 : conn_p = &(mca_p->conn);
659 : }
660 :
661 0 : if((conn_p->nettype == SDP_NT_ATM ) &&
662 0 : (conn_p->addrtype == SDP_AT_INVALID)) {
663 : /*allow c= line to be built without address type and address fields
664 : * This is a special case for ATM PVC*/
665 0 : flex_string_sprintf(fs, "c=%s\r\n",
666 : sdp_get_network_name(conn_p->nettype));
667 0 : return SDP_SUCCESS;
668 : }
669 0 : if ((conn_p->nettype >= SDP_MAX_NETWORK_TYPES) ||
670 0 : (conn_p->addrtype >= SDP_MAX_ADDR_TYPES) ||
671 0 : (conn_p->conn_addr[0] == '\0')) {
672 : /* Connection info isn't set - don't need to build the token. */
673 0 : return (SDP_SUCCESS);
674 : }
675 :
676 0 : if (conn_p->is_multicast) {
677 0 : if (conn_p->num_of_addresses > 1) {
678 0 : flex_string_sprintf(fs, "c=%s %s %s/%u/%u\r\n",
679 : sdp_get_network_name(conn_p->nettype),
680 : sdp_get_address_name(conn_p->addrtype),
681 0 : conn_p->conn_addr,
682 0 : (unsigned)conn_p->ttl,
683 0 : (unsigned)conn_p->num_of_addresses);
684 : } else {
685 0 : flex_string_sprintf(fs, "c=%s %s %s/%u\r\n",
686 : sdp_get_network_name(conn_p->nettype),
687 : sdp_get_address_name(conn_p->addrtype),
688 0 : conn_p->conn_addr,
689 0 : (unsigned)conn_p->ttl);
690 : }
691 : } else {
692 :
693 0 : flex_string_sprintf(fs, "c=%s %s %s\r\n",
694 : sdp_get_network_name(conn_p->nettype),
695 : sdp_get_address_name(conn_p->addrtype),
696 0 : conn_p->conn_addr);
697 : }
698 :
699 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
700 0 : SDP_PRINT("%s Built c= connection line", sdp_p->debug_str);
701 : }
702 0 : return (SDP_SUCCESS);
703 : }
704 :
705 : /*
706 : * sdp_parse_bandwidth
707 : *
708 : * This function parses a bandwidth field. The parsing is done in accordance
709 : * to the following ABNF:
710 : *
711 : * bandwidth-fields = *("b=" bwtype ":" bandwidth CRLF)
712 : * bwtype = 1*(alpha-numeric)
713 : * bandwidth = 1*(DIGIT)
714 : *
715 : * It currently supports three types of valid bwtypes - AS, CT and TIAS
716 : */
717 0 : sdp_result_e sdp_parse_bandwidth (sdp_t *sdp_p, uint16_t level, const char *ptr)
718 : {
719 : int i;
720 : sdp_mca_t *mca_p;
721 : sdp_bw_t *bw_p;
722 : sdp_bw_data_t *bw_data_p;
723 : sdp_bw_data_t *new_bw_data_p;
724 : sdp_result_e result;
725 : char tmp[SDP_MAX_STRING_LEN];
726 0 : sdp_bw_modifier_e bw_modifier = SDP_BW_MODIFIER_UNSUPPORTED;
727 0 : int bw_val = 0;
728 :
729 0 : if (level == SDP_SESSION_LEVEL) {
730 0 : bw_p = &(sdp_p->bw);
731 : } else {
732 0 : mca_p = sdp_find_media_level(sdp_p, level);
733 0 : if (mca_p == NULL) {
734 0 : return (SDP_FAILURE);
735 : }
736 0 : bw_p = &(mca_p->bw);
737 : }
738 :
739 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
740 0 : SDP_PRINT("%s Parse bandwidth line", sdp_p->debug_str);
741 : }
742 :
743 : /* Find the bw type (AS, CT or TIAS) */
744 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
745 0 : if (result != SDP_SUCCESS) {
746 0 : sdp_parse_error(sdp_p,
747 : "%s No bandwidth type specified for b= ",
748 0 : sdp_p->debug_str);
749 0 : sdp_p->conf_p->num_invalid_param++;
750 0 : return (SDP_INVALID_PARAMETER);
751 : }
752 0 : for (i=0; i < SDP_MAX_BW_MODIFIER_VAL; i++) {
753 0 : if (cpr_strncasecmp(tmp, sdp_bw_modifier_val[i].name,
754 0 : sdp_bw_modifier_val[i].strlen) == 0) {
755 0 : bw_modifier = (sdp_bw_modifier_e)i;
756 0 : break;
757 : }
758 : }
759 :
760 0 : if (bw_modifier == SDP_BW_MODIFIER_UNSUPPORTED) {
761 : /* We don't understand this parameter, so according to RFC4566 sec 5.8
762 : * ignore it. */
763 0 : return (SDP_SUCCESS);
764 : }
765 :
766 : /* Find the BW type value */
767 : /*sa_ignore NO_NULL_CHK
768 : {ptr is valid since the pointer was checked earlier and the
769 : function would have exited if NULL.}*/
770 0 : if (*ptr == ':') {
771 0 : ptr++;
772 0 : bw_val = sdp_getnextnumtok(ptr, &ptr, " \t", &result);
773 0 : if ((result != SDP_SUCCESS)) {
774 0 : sdp_parse_error(sdp_p,
775 : "%s Error: No BW Value specified ",
776 0 : sdp_p->debug_str);
777 0 : sdp_p->conf_p->num_invalid_param++;
778 0 : return (SDP_INVALID_PARAMETER);
779 : }
780 : }
781 :
782 : /*
783 : * Allocate a new sdp_bw_data_t instance and set it's values from the
784 : * input parameters.
785 : */
786 0 : new_bw_data_p = (sdp_bw_data_t*)SDP_MALLOC(sizeof(sdp_bw_data_t));
787 0 : if (new_bw_data_p == NULL) {
788 0 : sdp_p->conf_p->num_invalid_param++;
789 0 : return (SDP_NO_RESOURCE);
790 : }
791 0 : new_bw_data_p->next_p = NULL;
792 0 : new_bw_data_p->bw_modifier = bw_modifier;
793 0 : new_bw_data_p->bw_val = bw_val;
794 :
795 : /*
796 : * Enqueue the sdp_bw_data_t instance at the end of the list of
797 : * sdp_bw_data_t instances.
798 : */
799 0 : if (bw_p->bw_data_list == NULL) {
800 0 : bw_p->bw_data_list = new_bw_data_p;
801 : } else {
802 0 : for (bw_data_p = bw_p->bw_data_list;
803 0 : bw_data_p->next_p != NULL;
804 0 : bw_data_p = bw_data_p->next_p) {
805 : ; // Empty For
806 : }
807 0 : bw_data_p->next_p = new_bw_data_p;
808 : }
809 0 : bw_p->bw_data_count++;
810 :
811 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
812 0 : SDP_PRINT("%s Parsed bw type %s, value %d", sdp_p->debug_str,
813 : sdp_get_bw_modifier_name(new_bw_data_p->bw_modifier),
814 : new_bw_data_p->bw_val);
815 : }
816 :
817 0 : return (SDP_SUCCESS);
818 : }
819 :
820 : /*
821 : * sdp_build_bandwidth
822 : *
823 : * Builds *all* the bandwith lines for the specified level.
824 : */
825 0 : sdp_result_e sdp_build_bandwidth (sdp_t *sdp_p, uint16_t level, flex_string *fs)
826 : {
827 : sdp_bw_t *bw_p;
828 : sdp_bw_data_t *bw_data_p;
829 : sdp_mca_t *mca_p;
830 :
831 0 : if (level == SDP_SESSION_LEVEL) {
832 0 : bw_p = &(sdp_p->bw);
833 : } else {
834 0 : mca_p = sdp_find_media_level(sdp_p, level);
835 0 : if (mca_p == NULL) {
836 0 : return (SDP_FAILURE);
837 : }
838 0 : bw_p = &(mca_p->bw);
839 : }
840 :
841 0 : bw_data_p = bw_p->bw_data_list;
842 0 : while (bw_data_p) {
843 0 : flex_string_sprintf(fs, "b=%s:%d\r\n",
844 : sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
845 : bw_data_p->bw_val);
846 :
847 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
848 0 : SDP_PRINT("%s Built b=%s:%d bandwidth line", sdp_p->debug_str,
849 : sdp_get_bw_modifier_name(bw_data_p->bw_modifier),
850 : bw_data_p->bw_val);
851 : }
852 :
853 0 : bw_data_p = bw_data_p->next_p;
854 : }
855 :
856 0 : return (SDP_SUCCESS);
857 : }
858 :
859 0 : sdp_result_e sdp_parse_timespec (sdp_t *sdp_p, uint16_t level, const char *ptr)
860 : {
861 : char *tmpptr;
862 : sdp_result_e result;
863 : sdp_timespec_t *timespec_p;
864 : sdp_timespec_t *next_timespec_p;
865 :
866 0 : timespec_p = (sdp_timespec_t *)SDP_MALLOC(sizeof(sdp_timespec_t));
867 0 : if (timespec_p == NULL) {
868 0 : sdp_p->conf_p->num_no_resource++;
869 0 : return (SDP_NO_RESOURCE);
870 : }
871 :
872 : /* Validate start and stop times. */
873 0 : ptr = sdp_getnextstrtok(ptr, timespec_p->start_time, sizeof(timespec_p->start_time), " \t", &result);
874 0 : if (result == SDP_SUCCESS) {
875 : /* Make sure the start_time is numeric, even though we store it as
876 : * a string.
877 : */
878 0 : (void)sdp_getnextnumtok(timespec_p->start_time,
879 : (const char **)&tmpptr, " \t", &result);
880 : }
881 0 : if (result != SDP_SUCCESS) {
882 0 : sdp_parse_error(sdp_p,
883 : "%s Invalid timespec start time specified.",
884 0 : sdp_p->debug_str);
885 0 : sdp_p->conf_p->num_invalid_param++;
886 0 : SDP_FREE(timespec_p);
887 0 : return (SDP_INVALID_PARAMETER);
888 : }
889 :
890 0 : ptr = sdp_getnextstrtok(ptr, timespec_p->stop_time, sizeof(timespec_p->stop_time), " \t", &result);
891 0 : if (result == SDP_SUCCESS) {
892 : /* Make sure the start_time is numeric, even though we store it as
893 : * a string.
894 : */
895 0 : (void)sdp_getnextnumtok(timespec_p->stop_time,
896 : (const char **)&tmpptr, " \t", &result);
897 : }
898 0 : if (result != SDP_SUCCESS) {
899 0 : sdp_parse_error(sdp_p,
900 : "%s Invalid timespec stop time specified.",
901 0 : sdp_p->debug_str);
902 0 : sdp_p->conf_p->num_invalid_param++;
903 0 : SDP_FREE(timespec_p);
904 0 : return (SDP_INVALID_PARAMETER);
905 : }
906 :
907 : /* Link the new timespec in to the end of the list. */
908 0 : if (sdp_p->timespec_p == NULL) {
909 0 : sdp_p->timespec_p = timespec_p;
910 : } else {
911 0 : next_timespec_p = sdp_p->timespec_p;
912 0 : while (next_timespec_p->next_p != NULL) {
913 0 : next_timespec_p = next_timespec_p->next_p;
914 : }
915 0 : next_timespec_p->next_p = timespec_p;
916 : }
917 :
918 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
919 0 : SDP_PRINT("%s Parsed timespec line", sdp_p->debug_str);
920 : }
921 0 : return (SDP_SUCCESS);
922 : }
923 :
924 0 : sdp_result_e sdp_build_timespec (sdp_t *sdp_p, uint16_t level, flex_string *fs)
925 : {
926 0 : if ((sdp_p->timespec_p == NULL) ||
927 0 : (sdp_p->timespec_p->start_time[0] == '\0') ||
928 0 : (sdp_p->timespec_p->stop_time[0] == '\0')) {
929 0 : if (sdp_p->conf_p->timespec_reqd == TRUE) {
930 0 : CSFLogError(logTag, "%s Invalid params for t= time spec line, "
931 : "build failed.", sdp_p->debug_str);
932 0 : sdp_p->conf_p->num_invalid_param++;
933 0 : return (SDP_INVALID_PARAMETER);
934 : } else {
935 : /* t= line not required. */
936 0 : return (SDP_SUCCESS);
937 : }
938 : }
939 :
940 : /* Note: We only support one t= line currently. */
941 0 : flex_string_sprintf(fs, "t=%s %s\r\n", sdp_p->timespec_p->start_time,
942 0 : sdp_p->timespec_p->stop_time);
943 :
944 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
945 0 : SDP_PRINT("%s Built t= timespec line", sdp_p->debug_str);
946 : }
947 0 : return (SDP_SUCCESS);
948 : }
949 :
950 0 : sdp_result_e sdp_parse_repeat_time (sdp_t *sdp_p, uint16_t level, const char *ptr)
951 : {
952 : char *endptr;
953 :
954 0 : endptr = sdp_findchar(ptr, "\n");
955 0 : if (ptr == endptr) {
956 0 : sdp_parse_error(sdp_p,
957 : "%s Warning: No repeat time parameters "
958 0 : "specified.", sdp_p->debug_str);
959 : }
960 :
961 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
962 0 : SDP_PRINT("%s Parsed repeat time line", sdp_p->debug_str);
963 : }
964 0 : return (SDP_SUCCESS);
965 : }
966 :
967 0 : sdp_result_e sdp_build_repeat_time (sdp_t *sdp_p, uint16_t level, flex_string *fs)
968 : {
969 : /* Build repeat time line not supported. */
970 0 : return (SDP_SUCCESS);
971 : }
972 :
973 0 : sdp_result_e sdp_parse_timezone_adj (sdp_t *sdp_p, uint16_t level, const char *ptr)
974 : {
975 : char *endptr;
976 :
977 0 : endptr = sdp_findchar(ptr, "\n");
978 0 : if (ptr == endptr) {
979 0 : sdp_parse_error(sdp_p,
980 : "%s Warning: No timezone parameters specified.",
981 0 : sdp_p->debug_str);
982 : }
983 :
984 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
985 0 : SDP_PRINT("%s Parse timezone adustment line", sdp_p->debug_str);
986 : }
987 0 : return (SDP_SUCCESS);
988 : }
989 :
990 0 : sdp_result_e sdp_build_timezone_adj (sdp_t *sdp_p, uint16_t level, flex_string *fs)
991 : {
992 : /* Build timezone adjustment line not supported. */
993 0 : return (SDP_SUCCESS);
994 : }
995 :
996 0 : sdp_result_e sdp_parse_encryption (sdp_t *sdp_p, uint16_t level, const char *ptr)
997 : {
998 : int i;
999 : sdp_result_e result;
1000 : sdp_encryptspec_t *encrypt_p;
1001 : sdp_mca_t *mca_p;
1002 : char tmp[SDP_MAX_STRING_LEN];
1003 :
1004 0 : if (level == SDP_SESSION_LEVEL) {
1005 0 : encrypt_p = &(sdp_p->encrypt);
1006 : } else {
1007 0 : mca_p = sdp_find_media_level(sdp_p, level);
1008 0 : if (mca_p == NULL) {
1009 0 : return (SDP_FAILURE);
1010 : }
1011 0 : encrypt_p = &(mca_p->encrypt);
1012 : }
1013 0 : encrypt_p->encrypt_key[0] = '\0';
1014 :
1015 : /* Find the encryption type. */
1016 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), ":", &result);
1017 0 : if (result != SDP_SUCCESS) {
1018 0 : sdp_parse_error(sdp_p,
1019 : "%s No encryption type specified for k=.",
1020 0 : sdp_p->debug_str);
1021 0 : sdp_p->conf_p->num_invalid_param++;
1022 0 : return (SDP_INVALID_PARAMETER);
1023 : }
1024 0 : encrypt_p->encrypt_type = SDP_ENCRYPT_UNSUPPORTED;
1025 0 : for (i=0; i < SDP_MAX_ENCRYPT_TYPES; i++) {
1026 0 : if (cpr_strncasecmp(tmp, sdp_encrypt[i].name,
1027 0 : sdp_encrypt[i].strlen) == 0) {
1028 0 : encrypt_p->encrypt_type = (sdp_encrypt_type_e)i;
1029 0 : break;
1030 : }
1031 : }
1032 0 : if (encrypt_p->encrypt_type == SDP_ENCRYPT_UNSUPPORTED) {
1033 0 : sdp_parse_error(sdp_p,
1034 : "%s Warning: Encryption type unsupported (%s).",
1035 0 : sdp_p->debug_str, tmp);
1036 : }
1037 :
1038 : /* Find the encryption key. */
1039 0 : encrypt_p->encrypt_key[0] = '\0';
1040 : /*sa_ignore NO_NULL_CHK
1041 : {ptr is valid since the pointer was checked earlier and the
1042 : function would have exited if NULL.}*/
1043 0 : if (*ptr == ':')
1044 0 : ptr++;
1045 0 : if (encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) {
1046 0 : ptr = sdp_getnextstrtok(ptr, encrypt_p->encrypt_key, sizeof(encrypt_p->encrypt_key), " \t", &result);
1047 0 : if ((result != SDP_SUCCESS) &&
1048 0 : ((encrypt_p->encrypt_type == SDP_ENCRYPT_CLEAR) ||
1049 0 : (encrypt_p->encrypt_type == SDP_ENCRYPT_BASE64) ||
1050 0 : (encrypt_p->encrypt_type == SDP_ENCRYPT_URI))) {
1051 0 : sdp_parse_error(sdp_p,
1052 : "%s Warning: No encryption key specified "
1053 0 : "as required.", sdp_p->debug_str);
1054 0 : sdp_p->conf_p->num_invalid_param++;
1055 0 : return (SDP_INVALID_PARAMETER);
1056 : }
1057 : }
1058 :
1059 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1060 0 : SDP_PRINT("%s Parse encryption type %s, key %s", sdp_p->debug_str,
1061 : sdp_get_encrypt_name(encrypt_p->encrypt_type),
1062 : encrypt_p->encrypt_key);
1063 : }
1064 0 : return (SDP_SUCCESS);
1065 : }
1066 :
1067 : /* If the encryption info is valid, we build it. Else skip it. */
1068 0 : sdp_result_e sdp_build_encryption (sdp_t *sdp_p, uint16_t level, flex_string *fs)
1069 : {
1070 : sdp_encryptspec_t *encrypt_p;
1071 : sdp_mca_t *mca_p;
1072 :
1073 0 : if (level == SDP_SESSION_LEVEL) {
1074 0 : encrypt_p = &(sdp_p->encrypt);
1075 : } else {
1076 0 : mca_p = sdp_find_media_level(sdp_p, level);
1077 0 : if (mca_p == NULL) {
1078 0 : return (SDP_FAILURE);
1079 : }
1080 0 : encrypt_p = &(mca_p->encrypt);
1081 : }
1082 :
1083 0 : if ((encrypt_p->encrypt_type >= SDP_MAX_ENCRYPT_TYPES) ||
1084 0 : ((encrypt_p->encrypt_type != SDP_ENCRYPT_PROMPT) &&
1085 0 : (encrypt_p->encrypt_key[0] == '\0'))) {
1086 : /* Encryption info isn't set - don't need to build the token. */
1087 0 : return (SDP_SUCCESS);
1088 : }
1089 :
1090 0 : flex_string_sprintf(fs, "k=%s",
1091 : sdp_get_encrypt_name(encrypt_p->encrypt_type));
1092 :
1093 0 : if (encrypt_p->encrypt_type == SDP_ENCRYPT_PROMPT) {
1094 : /* There is no key to print. */
1095 0 : flex_string_sprintf(fs, "\r\n");
1096 : } else {
1097 0 : flex_string_sprintf(fs, ":%s\r\n", encrypt_p->encrypt_key);
1098 : }
1099 :
1100 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1101 0 : SDP_PRINT("%s Built k= encryption line", sdp_p->debug_str);
1102 : }
1103 0 : return (SDP_SUCCESS);
1104 : }
1105 :
1106 0 : sdp_result_e sdp_parse_media (sdp_t *sdp_p, uint16_t level, const char *ptr)
1107 : {
1108 : uint16_t i;
1109 0 : uint16_t num_port_params=0;
1110 : int32_t num[SDP_MAX_PORT_PARAMS];
1111 0 : tinybool valid_param = FALSE;
1112 : sdp_result_e result;
1113 : sdp_mca_t *mca_p;
1114 : sdp_mca_t *next_mca_p;
1115 : char tmp[SDP_MAX_STRING_LEN];
1116 : char port[SDP_MAX_STRING_LEN];
1117 : const char *port_ptr;
1118 : int32_t sctp_port;
1119 :
1120 : /* Allocate resource for new media stream. */
1121 0 : mca_p = sdp_alloc_mca(sdp_p->parse_line);
1122 0 : if (mca_p == NULL) {
1123 0 : sdp_p->conf_p->num_no_resource++;
1124 0 : return (SDP_NO_RESOURCE);
1125 : }
1126 :
1127 : /* Find the media type. */
1128 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1129 0 : if (result != SDP_SUCCESS) {
1130 0 : sdp_parse_error(sdp_p,
1131 : "%s No media type specified, parse failed.",
1132 0 : sdp_p->debug_str);
1133 0 : SDP_FREE(mca_p);
1134 0 : sdp_p->conf_p->num_invalid_param++;
1135 0 : return (SDP_INVALID_PARAMETER);
1136 : }
1137 0 : mca_p->media = SDP_MEDIA_UNSUPPORTED;
1138 0 : for (i=0; i < SDP_MAX_MEDIA_TYPES; i++) {
1139 0 : if (cpr_strncasecmp(tmp, sdp_media[i].name,
1140 0 : sdp_media[i].strlen) == 0) {
1141 0 : mca_p->media = (sdp_media_e)i;
1142 : }
1143 : }
1144 0 : if (mca_p->media == SDP_MEDIA_UNSUPPORTED) {
1145 0 : sdp_parse_error(sdp_p,
1146 : "%s Warning: Media type unsupported (%s).",
1147 0 : sdp_p->debug_str, tmp);
1148 : }
1149 :
1150 : /* Find the port token parameters, but don't process it until
1151 : * we determine the transport protocol as that determines what
1152 : * port number formats are valid.
1153 : */
1154 0 : ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
1155 0 : if (result != SDP_SUCCESS) {
1156 0 : sdp_parse_error(sdp_p,
1157 : "%s No port specified in m= media line, "
1158 0 : "parse failed.", sdp_p->debug_str);
1159 0 : SDP_FREE(mca_p);
1160 0 : sdp_p->conf_p->num_invalid_param++;
1161 0 : return (SDP_INVALID_PARAMETER);
1162 : }
1163 0 : port_ptr = port;
1164 0 : for (i=0; i < SDP_MAX_PORT_PARAMS; i++) {
1165 0 : if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result) == TRUE) {
1166 0 : num[i] = SDP_CHOOSE_PARAM;
1167 : } else {
1168 0 : num[i] = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
1169 : "/ \t", &result);
1170 0 : if (result != SDP_SUCCESS) {
1171 0 : break;
1172 : }
1173 : }
1174 0 : num_port_params++;
1175 : }
1176 :
1177 : /* Find the transport protocol type. */
1178 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1179 0 : if (result != SDP_SUCCESS) {
1180 0 : sdp_parse_error(sdp_p,
1181 : "%s No transport protocol type specified, "
1182 0 : "parse failed.", sdp_p->debug_str);
1183 0 : SDP_FREE(mca_p);
1184 0 : sdp_p->conf_p->num_invalid_param++;
1185 0 : return (SDP_INVALID_PARAMETER);
1186 : }
1187 0 : mca_p->transport = SDP_TRANSPORT_UNSUPPORTED;
1188 0 : for (i=0; i < SDP_MAX_TRANSPORT_TYPES; i++) {
1189 0 : if (cpr_strncasecmp(tmp, sdp_transport[i].name,
1190 0 : sdp_transport[i].strlen) == 0) {
1191 0 : mca_p->transport = (sdp_transport_e)i;
1192 0 : break;
1193 : }
1194 : }
1195 :
1196 0 : if (mca_p->transport == SDP_TRANSPORT_UNSUPPORTED) {
1197 : /* If we don't recognize or don't support the transport type,
1198 : * just store the first num as the port.
1199 : */
1200 0 : mca_p->port = num[0];
1201 0 : sdp_parse_error(sdp_p,
1202 : "%s Warning: Transport protocol type unsupported "
1203 0 : "(%s).", sdp_p->debug_str, tmp);
1204 : }
1205 :
1206 : /* Check for each of the possible port formats according to the
1207 : * type of transport protocol specified.
1208 : */
1209 0 : valid_param = FALSE;
1210 0 : switch (num_port_params) {
1211 : case 1:
1212 0 : if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
1213 0 : (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
1214 0 : (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
1215 0 : (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
1216 0 : (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
1217 0 : (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVP) ||
1218 0 : (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVPF) ||
1219 0 : (mca_p->transport == SDP_TRANSPORT_UDP) ||
1220 0 : (mca_p->transport == SDP_TRANSPORT_TCP) ||
1221 0 : (mca_p->transport == SDP_TRANSPORT_UDPTL) ||
1222 0 : (mca_p->transport == SDP_TRANSPORT_UDPSPRT) ||
1223 0 : (mca_p->transport == SDP_TRANSPORT_LOCAL) ||
1224 0 : (mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
1225 0 : (mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1226 0 : (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1227 : /* Port format is simply <port>. Make sure that either
1228 : * the choose param is allowed or that the choose value
1229 : * wasn't specified.
1230 : */
1231 0 : if ((sdp_p->conf_p->allow_choose[SDP_CHOOSE_PORTNUM]) ||
1232 0 : (num[0] != SDP_CHOOSE_PARAM)) {
1233 0 : mca_p->port = num[0];
1234 0 : mca_p->port_format = SDP_PORT_NUM_ONLY;
1235 0 : valid_param = TRUE;
1236 : }
1237 0 : } else if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
1238 : /* Port format is simply <vcci>, choose param is not allowed.
1239 : */
1240 0 : if (num[0] != SDP_CHOOSE_PARAM) {
1241 0 : mca_p->vcci = num[0];
1242 0 : mca_p->port_format = SDP_PORT_VCCI;
1243 0 : valid_param = TRUE;
1244 : }
1245 0 : } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1246 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1247 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1248 : /* Port format is simply <port>, and choose param is allowed,
1249 : * according to AAL2 definitions.
1250 : */
1251 0 : mca_p->port = num[0];
1252 0 : mca_p->port_format = SDP_PORT_NUM_ONLY;
1253 0 : valid_param = TRUE;
1254 : }
1255 0 : break;
1256 : case 2:
1257 0 : if ((mca_p->transport == SDP_TRANSPORT_RTPAVP) ||
1258 0 : (mca_p->transport == SDP_TRANSPORT_RTPSAVP) ||
1259 0 : (mca_p->transport == SDP_TRANSPORT_RTPSAVPF) ||
1260 0 : (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVP) ||
1261 0 : (mca_p->transport == SDP_TRANSPORT_UDPTLSRTPSAVPF) ||
1262 0 : (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVP) ||
1263 0 : (mca_p->transport == SDP_TRANSPORT_TCPTLSRTPSAVPF) ||
1264 0 : (mca_p->transport == SDP_TRANSPORT_UDP) ||
1265 0 : (mca_p->transport == SDP_TRANSPORT_LOCAL)) {
1266 : /* Port format is <port>/<num of ports>. Make sure choose
1267 : * params were not specified.
1268 : */
1269 0 : if ((num[0] != SDP_CHOOSE_PARAM) &&
1270 0 : (num[1] != SDP_CHOOSE_PARAM)) {
1271 0 : mca_p->port = num[0];
1272 0 : mca_p->num_ports = num[1];
1273 0 : mca_p->port_format = SDP_PORT_NUM_COUNT;
1274 0 : valid_param = TRUE;
1275 : }
1276 0 : } else if (mca_p->transport == SDP_TRANSPORT_UDPTL) {
1277 : /* Port format is <port>/<num of ports>. Make sure choose
1278 : * params were not specified. For UDPTL, only "1" may
1279 : * be specified for number of ports.
1280 : */
1281 0 : if ((num[0] != SDP_CHOOSE_PARAM) &&
1282 0 : (num[1] == 1)) {
1283 0 : mca_p->port = num[0];
1284 0 : mca_p->num_ports = 1;
1285 0 : mca_p->port_format = SDP_PORT_NUM_COUNT;
1286 0 : valid_param = TRUE;
1287 : }
1288 0 : } else if (mca_p->transport == SDP_TRANSPORT_CES10) {
1289 : /* Port format is <vpi>/<vci>. Make sure choose
1290 : * params were not specified.
1291 : */
1292 0 : if ((num[0] != SDP_CHOOSE_PARAM) &&
1293 0 : (num[1] != SDP_CHOOSE_PARAM)) {
1294 0 : mca_p->vpi = num[0];
1295 0 : mca_p->vci = num[1];
1296 0 : mca_p->port_format = SDP_PORT_VPI_VCI;
1297 0 : valid_param = TRUE;
1298 : }
1299 0 : } else if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1300 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1301 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1302 : /* Port format is either <vcci>/<cid> or $/$. If one
1303 : * param is '$' the other must be also. The choose params
1304 : * are allowed by default and don't need to be allowed
1305 : * through the appl config.
1306 : */
1307 0 : if (((num[0] != SDP_CHOOSE_PARAM) &&
1308 0 : (num[1] != SDP_CHOOSE_PARAM)) ||
1309 0 : ((num[0] == SDP_CHOOSE_PARAM) &&
1310 0 : (num[1] == SDP_CHOOSE_PARAM))) {
1311 0 : mca_p->vcci = num[0];
1312 0 : mca_p->cid = num[1];
1313 0 : mca_p->port_format = SDP_PORT_VCCI_CID;
1314 0 : valid_param = TRUE;
1315 : }
1316 : }
1317 0 : break;
1318 : case 3:
1319 0 : if (mca_p->transport == SDP_TRANSPORT_AAL1AVP) {
1320 : /* Port format is <port>/<vpi>/<vci>. Make sure choose
1321 : * params were not specified.
1322 : */
1323 0 : if ((num[0] != SDP_CHOOSE_PARAM) &&
1324 0 : (num[1] != SDP_CHOOSE_PARAM) &&
1325 0 : (num[2] != SDP_CHOOSE_PARAM)) {
1326 0 : mca_p->port = num[0];
1327 0 : mca_p->vpi = num[1];
1328 0 : mca_p->vci = num[2];
1329 0 : mca_p->port_format = SDP_PORT_NUM_VPI_VCI;
1330 0 : valid_param = TRUE;
1331 : }
1332 : }
1333 0 : break;
1334 : case 4:
1335 0 : if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1336 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1337 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1338 : /* Port format is <port>/<vpi>/<vci>/<cid>. Make sure choose
1339 : * params were not specified.
1340 : */
1341 0 : if ((num[0] != SDP_CHOOSE_PARAM) &&
1342 0 : (num[1] != SDP_CHOOSE_PARAM) &&
1343 0 : (num[2] != SDP_CHOOSE_PARAM) &&
1344 0 : (num[3] != SDP_CHOOSE_PARAM)) {
1345 0 : mca_p->port = num[0];
1346 0 : mca_p->vpi = num[1];
1347 0 : mca_p->vci = num[2];
1348 0 : mca_p->cid = num[3];
1349 0 : mca_p->port_format = SDP_PORT_NUM_VPI_VCI_CID;
1350 0 : valid_param = TRUE;
1351 : }
1352 : }
1353 0 : break;
1354 : }
1355 0 : if (valid_param == FALSE) {
1356 0 : sdp_parse_error(sdp_p,
1357 : "%s Invalid port format (%s) specified for transport "
1358 0 : "protocol (%s), parse failed.", sdp_p->debug_str,
1359 : port, sdp_get_transport_name(mca_p->transport));
1360 0 : sdp_p->conf_p->num_invalid_param++;
1361 0 : SDP_FREE(mca_p);
1362 0 : return (SDP_INVALID_PARAMETER);
1363 : }
1364 :
1365 : /* Find payload formats. AAL2 media lines allow multiple
1366 : * transport/profile types per line, so these are handled differently. */
1367 0 : if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1368 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1369 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1370 :
1371 0 : if (sdp_parse_multiple_profile_payload_types(sdp_p, mca_p, ptr) !=
1372 : SDP_SUCCESS) {
1373 0 : sdp_p->conf_p->num_invalid_param++;
1374 0 : SDP_FREE(mca_p);
1375 0 : return (SDP_INVALID_PARAMETER);
1376 : }
1377 : /* Parse DTLS/SCTP port */
1378 0 : } else if ((mca_p->transport == SDP_TRANSPORT_DTLSSCTP) ||
1379 0 : (mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1380 0 : (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1381 0 : ptr = sdp_getnextstrtok(ptr, port, sizeof(port), " \t", &result);
1382 0 : if (result != SDP_SUCCESS) {
1383 0 : sdp_parse_error(sdp_p,
1384 : "%s No sctp port specified in m= media line, "
1385 0 : "parse failed.", sdp_p->debug_str);
1386 0 : SDP_FREE(mca_p);
1387 0 : sdp_p->conf_p->num_invalid_param++;
1388 0 : return (SDP_INVALID_PARAMETER);
1389 : }
1390 0 : port_ptr = port;
1391 :
1392 0 : if ((mca_p->transport == SDP_TRANSPORT_UDPDTLSSCTP) ||
1393 0 : (mca_p->transport == SDP_TRANSPORT_TCPDTLSSCTP)) {
1394 0 : if (cpr_strncasecmp(port_ptr, "webrtc-datachannel",
1395 : sizeof("webrtc-datachannel")) != 0) {
1396 0 : sdp_parse_error(sdp_p,
1397 : "%s No webrtc-datachannel token in m= media line, "
1398 0 : "parse failed.", sdp_p->debug_str);
1399 0 : SDP_FREE(mca_p);
1400 0 : sdp_p->conf_p->num_invalid_param++;
1401 0 : return (SDP_INVALID_PARAMETER);
1402 : }
1403 0 : mca_p->sctp_fmt = SDP_SCTP_MEDIA_FMT_WEBRTC_DATACHANNEL;
1404 0 : } else if (sdp_getchoosetok(port_ptr, &port_ptr, "/ \t", &result)) {
1405 0 : sctp_port = SDP_CHOOSE_PARAM;
1406 : } else {
1407 0 : sctp_port = sdp_getnextnumtok(port_ptr, (const char **)&port_ptr,
1408 : "/ \t", &result);
1409 0 : if (result != SDP_SUCCESS) {
1410 0 : sdp_parse_error(sdp_p,
1411 : "%s No sctp port specified in m= media line, "
1412 0 : "parse failed.", sdp_p->debug_str);
1413 0 : SDP_FREE(mca_p);
1414 0 : sdp_p->conf_p->num_invalid_param++;
1415 0 : return (SDP_INVALID_PARAMETER);
1416 : }
1417 0 : mca_p->sctpport = sctp_port;
1418 : }
1419 : } else {
1420 : /* Transport is a non-AAL2 type and not SCTP. Parse payloads
1421 : normally. */
1422 0 : sdp_parse_payload_types(sdp_p, mca_p, ptr);
1423 : }
1424 :
1425 :
1426 : /* Media line params are valid. Add it into the SDP. */
1427 0 : sdp_p->mca_count++;
1428 0 : if (sdp_p->mca_p == NULL) {
1429 0 : sdp_p->mca_p = mca_p;
1430 : } else {
1431 0 : for (next_mca_p = sdp_p->mca_p; next_mca_p->next_p != NULL;
1432 0 : next_mca_p = next_mca_p->next_p) {
1433 : ; // Empty For
1434 : }
1435 0 : next_mca_p->next_p = mca_p;
1436 : }
1437 :
1438 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1439 :
1440 0 : SDP_PRINT("%s Parsed media type %s, ", sdp_p->debug_str,
1441 : sdp_get_media_name(mca_p->media));
1442 0 : switch (mca_p->port_format) {
1443 : case SDP_PORT_NUM_ONLY:
1444 0 : SDP_PRINT("Port num %d, ", mca_p->port);
1445 0 : break;
1446 :
1447 : case SDP_PORT_NUM_COUNT:
1448 0 : SDP_PRINT("Port num %d, count %d, ",
1449 : mca_p->port, mca_p->num_ports);
1450 0 : break;
1451 : case SDP_PORT_VPI_VCI:
1452 0 : SDP_PRINT("VPI/VCI %d/%u, ", mca_p->vpi, mca_p->vci);
1453 0 : break;
1454 : case SDP_PORT_VCCI:
1455 0 : SDP_PRINT("VCCI %d, ", mca_p->vcci);
1456 0 : break;
1457 : case SDP_PORT_NUM_VPI_VCI:
1458 0 : SDP_PRINT("Port %d, VPI/VCI %d/%u, ", mca_p->port,
1459 : mca_p->vpi, mca_p->vci);
1460 0 : break;
1461 : case SDP_PORT_VCCI_CID:
1462 0 : SDP_PRINT("VCCI %d, CID %d, ", mca_p->vcci, mca_p->cid);
1463 0 : break;
1464 : case SDP_PORT_NUM_VPI_VCI_CID:
1465 0 : SDP_PRINT("Port %d, VPI/VCI %d/%u, CID %d, ", mca_p->port,
1466 : mca_p->vpi, mca_p->vci, mca_p->cid);
1467 0 : break;
1468 : default:
1469 0 : SDP_PRINT("Port format not valid, ");
1470 0 : break;
1471 : }
1472 :
1473 0 : if ((mca_p->transport >= SDP_TRANSPORT_AAL2_ITU) &&
1474 0 : (mca_p->transport <= SDP_TRANSPORT_AAL2_CUSTOM)) {
1475 0 : for (i=0; i < mca_p->media_profiles_p->num_profiles; i++) {
1476 0 : SDP_PRINT("Profile %s, Num payloads %u ",
1477 : sdp_get_transport_name(mca_p->media_profiles_p->profile[i]),
1478 : (unsigned)mca_p->media_profiles_p->num_payloads[i]);
1479 : }
1480 : } else {
1481 0 : SDP_PRINT("Transport %s, Num payloads %u",
1482 : sdp_get_transport_name(mca_p->transport),
1483 : (unsigned)mca_p->num_payloads);
1484 : }
1485 : }
1486 0 : return (SDP_SUCCESS);
1487 : }
1488 :
1489 0 : sdp_result_e sdp_build_media (sdp_t *sdp_p, uint16_t level, flex_string *fs)
1490 : {
1491 : int i, j;
1492 : sdp_mca_t *mca_p;
1493 0 : tinybool invalid_params=FALSE;
1494 : sdp_media_profiles_t *profile_p;
1495 :
1496 : /* Find the right media line */
1497 0 : mca_p = sdp_find_media_level(sdp_p, level);
1498 0 : if (mca_p == NULL) {
1499 0 : return (SDP_FAILURE);
1500 : }
1501 :
1502 : /* Validate params for this media line */
1503 0 : if ((mca_p->media >= SDP_MAX_MEDIA_TYPES) ||
1504 0 : (mca_p->port_format >= SDP_MAX_PORT_FORMAT_TYPES) ||
1505 0 : (mca_p->transport >= SDP_MAX_TRANSPORT_TYPES)) {
1506 0 : invalid_params = TRUE;
1507 : }
1508 :
1509 0 : if (invalid_params == TRUE) {
1510 0 : CSFLogError(logTag, "%s Invalid params for m= media line, "
1511 : "build failed.", sdp_p->debug_str);
1512 0 : sdp_p->conf_p->num_invalid_param++;
1513 0 : return (SDP_INVALID_PARAMETER);
1514 : }
1515 :
1516 : /* Build the media type */
1517 0 : flex_string_sprintf(fs, "m=%s ", sdp_get_media_name(mca_p->media));
1518 :
1519 : /* Build the port based on the specified port format */
1520 0 : if (mca_p->port_format == SDP_PORT_NUM_ONLY) {
1521 0 : if (mca_p->port == SDP_CHOOSE_PARAM) {
1522 0 : flex_string_sprintf(fs, "$ ");
1523 : } else {
1524 0 : flex_string_sprintf(fs, "%u ", (unsigned)mca_p->port);
1525 : }
1526 0 : } else if (mca_p->port_format == SDP_PORT_NUM_COUNT) {
1527 0 : flex_string_sprintf(fs, "%u/%u ", (unsigned)mca_p->port,
1528 0 : (unsigned)mca_p->num_ports);
1529 0 : } else if (mca_p->port_format == SDP_PORT_VPI_VCI) {
1530 0 : flex_string_sprintf(fs, "%u/%u ",
1531 0 : (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
1532 0 : } else if (mca_p->port_format == SDP_PORT_VCCI) {
1533 0 : flex_string_sprintf(fs, "%u ", (unsigned)mca_p->vcci);
1534 0 : } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI) {
1535 0 : flex_string_sprintf(fs, "%u/%u/%u ", (unsigned)mca_p->port,
1536 0 : (unsigned)mca_p->vpi, (unsigned)mca_p->vci);
1537 0 : } else if (mca_p->port_format == SDP_PORT_VCCI_CID) {
1538 0 : if ((mca_p->vcci == SDP_CHOOSE_PARAM) &&
1539 0 : (mca_p->cid == SDP_CHOOSE_PARAM)) {
1540 0 : flex_string_sprintf(fs, "$/$ ");
1541 0 : } else if ((mca_p->vcci == SDP_CHOOSE_PARAM) ||
1542 0 : (mca_p->cid == SDP_CHOOSE_PARAM)) {
1543 : /* If one is set but not the other, this is an error. */
1544 0 : CSFLogError(logTag, "%s Invalid params for m= port parameter, "
1545 : "build failed.", sdp_p->debug_str);
1546 0 : sdp_p->conf_p->num_invalid_param++;
1547 0 : return (SDP_INVALID_PARAMETER);
1548 : } else {
1549 0 : flex_string_sprintf(fs, "%u/%u ",
1550 0 : (unsigned)mca_p->vcci, (unsigned)mca_p->cid);
1551 : }
1552 0 : } else if (mca_p->port_format == SDP_PORT_NUM_VPI_VCI_CID) {
1553 0 : flex_string_sprintf(fs, "%u/%u/%u/%u ", (unsigned)mca_p->port,
1554 0 : (unsigned)mca_p->vpi, (unsigned)mca_p->vci, (unsigned)mca_p->cid);
1555 : }
1556 :
1557 : /* If the media line has AAL2 profiles, build them differently. */
1558 0 : if ((mca_p->transport == SDP_TRANSPORT_AAL2_ITU) ||
1559 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_ATMF) ||
1560 0 : (mca_p->transport == SDP_TRANSPORT_AAL2_CUSTOM)) {
1561 0 : profile_p = mca_p->media_profiles_p;
1562 0 : for (i=0; i < profile_p->num_profiles; i++) {
1563 0 : flex_string_sprintf(fs, "%s",
1564 : sdp_get_transport_name(profile_p->profile[i]));
1565 :
1566 0 : for (j=0; j < profile_p->num_payloads[i]; j++) {
1567 0 : flex_string_sprintf(fs, " %u",
1568 0 : (unsigned)profile_p->payload_type[i][j]);
1569 : }
1570 0 : flex_string_sprintf(fs, " ");
1571 : }
1572 0 : flex_string_sprintf(fs, "\n");
1573 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1574 0 : SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
1575 : }
1576 0 : return (SDP_SUCCESS);
1577 : }
1578 :
1579 : /* Build the transport name */
1580 0 : flex_string_sprintf(fs, "%s",
1581 : sdp_get_transport_name(mca_p->transport));
1582 :
1583 0 : if(mca_p->transport != SDP_TRANSPORT_DTLSSCTP) {
1584 :
1585 : /* Build the format lists */
1586 0 : for (i=0; i < mca_p->num_payloads; i++) {
1587 0 : if (mca_p->payload_indicator[i] == SDP_PAYLOAD_ENUM) {
1588 0 : flex_string_sprintf(fs, " %s",
1589 0 : sdp_get_payload_name((sdp_payload_e)mca_p->payload_type[i]));
1590 : } else {
1591 0 : flex_string_sprintf(fs, " %u", (unsigned)mca_p->payload_type[i]);
1592 : }
1593 : }
1594 : } else {
1595 : /* Add port to SDP if transport is DTLS/SCTP */
1596 0 : flex_string_sprintf(fs, " %u", (unsigned)mca_p->sctpport);
1597 : }
1598 :
1599 0 : flex_string_sprintf(fs, "\r\n");
1600 :
1601 0 : if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
1602 0 : SDP_PRINT("%s Built m= media line", sdp_p->debug_str);
1603 : }
1604 0 : return (SDP_SUCCESS);
1605 : }
1606 :
1607 :
1608 : /* Function: sdp_parse_payload_types
1609 : * Description: Parse a list of payload types. The list may be part of
1610 : * a media line or part of a capability line.
1611 : * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
1612 : * mca_p The mca structure the payload types should be
1613 : * added to.
1614 : * ptr The pointer to the list of payloads.
1615 : * Returns: Nothing.
1616 : */
1617 0 : void sdp_parse_payload_types (sdp_t *sdp_p, sdp_mca_t *mca_p, const char *ptr)
1618 : {
1619 : uint16_t i;
1620 : uint16_t num_payloads;
1621 : sdp_result_e result;
1622 : tinybool valid_payload;
1623 : char tmp[SDP_MAX_STRING_LEN];
1624 : char *tmp2;
1625 :
1626 0 : for (num_payloads = 0; (num_payloads < SDP_MAX_PAYLOAD_TYPES); ) {
1627 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1628 0 : if (result != SDP_SUCCESS) {
1629 : /* If there are no more payload types, we're finished */
1630 0 : break;
1631 : }
1632 0 : mca_p->payload_type[num_payloads] = (uint16_t)sdp_getnextnumtok(tmp,
1633 : (const char **)&tmp2,
1634 : " \t", &result);
1635 0 : if (result == SDP_SUCCESS) {
1636 0 : if ((mca_p->media == SDP_MEDIA_IMAGE) &&
1637 0 : (mca_p->transport == SDP_TRANSPORT_UDPTL)) {
1638 0 : sdp_parse_error(sdp_p,
1639 : "%s Warning: Numeric payload type not "
1640 : "valid for media %s with transport %s.",
1641 0 : sdp_p->debug_str,
1642 : sdp_get_media_name(mca_p->media),
1643 : sdp_get_transport_name(mca_p->transport));
1644 : } else {
1645 0 : mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_NUMERIC;
1646 0 : mca_p->num_payloads++;
1647 0 : num_payloads++;
1648 : }
1649 0 : continue;
1650 : }
1651 :
1652 0 : valid_payload = FALSE;
1653 0 : for (i=0; i < SDP_MAX_STRING_PAYLOAD_TYPES; i++) {
1654 0 : if (cpr_strncasecmp(tmp, sdp_payload[i].name,
1655 0 : sdp_payload[i].strlen) == 0) {
1656 0 : valid_payload = TRUE;
1657 0 : break;
1658 : }
1659 : }
1660 0 : if (valid_payload == TRUE) {
1661 : /* We recognized the payload type. Make sure it
1662 : * is valid for this media line. */
1663 0 : valid_payload = FALSE;
1664 0 : if ((mca_p->media == SDP_MEDIA_IMAGE) &&
1665 0 : (mca_p->transport == SDP_TRANSPORT_UDPTL) &&
1666 : (i == SDP_PAYLOAD_T38)) {
1667 0 : valid_payload = TRUE;
1668 0 : } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
1669 0 : (mca_p->transport == SDP_TRANSPORT_UDP) &&
1670 : (i == SDP_PAYLOAD_XTMR)) {
1671 0 : valid_payload = TRUE;
1672 0 : } else if ((mca_p->media == SDP_MEDIA_APPLICATION) &&
1673 0 : (mca_p->transport == SDP_TRANSPORT_TCP) &&
1674 : (i == SDP_PAYLOAD_T120)) {
1675 0 : valid_payload = TRUE;
1676 : }
1677 :
1678 0 : if (valid_payload == TRUE) {
1679 0 : mca_p->payload_indicator[num_payloads] = SDP_PAYLOAD_ENUM;
1680 0 : mca_p->payload_type[num_payloads] = i;
1681 0 : mca_p->num_payloads++;
1682 0 : num_payloads++;
1683 : } else {
1684 0 : sdp_parse_error(sdp_p,
1685 : "%s Warning: Payload type %s not valid for "
1686 : "media %s with transport %s.",
1687 0 : sdp_p->debug_str,
1688 : sdp_get_payload_name((sdp_payload_e)i),
1689 : sdp_get_media_name(mca_p->media),
1690 : sdp_get_transport_name(mca_p->transport));
1691 : }
1692 : } else {
1693 : /* Payload type wasn't recognized. */
1694 0 : sdp_parse_error(sdp_p,
1695 : "%s Warning: Payload type "
1696 0 : "unsupported (%s).", sdp_p->debug_str, tmp);
1697 : }
1698 : }
1699 0 : if (mca_p->num_payloads == 0) {
1700 0 : sdp_parse_error(sdp_p,
1701 : "%s Warning: No payload types specified.",
1702 0 : sdp_p->debug_str);
1703 : }
1704 0 : }
1705 :
1706 :
1707 : /* Function: sdp_parse_multiple_profile_payload_types
1708 : * Description: Parse a list of payload types. The list may be part of
1709 : * a media line or part of a capability line.
1710 : * Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
1711 : * mca_p The mca structure the payload types should be
1712 : * added to.
1713 : * ptr The pointer to the list of payloads.
1714 : * Returns: Nothing.
1715 : */
1716 0 : sdp_result_e sdp_parse_multiple_profile_payload_types (sdp_t *sdp_p,
1717 : sdp_mca_t *mca_p,
1718 : const char *ptr)
1719 : {
1720 : uint16_t i;
1721 : uint16_t prof;
1722 : uint16_t payload;
1723 : sdp_result_e result;
1724 : sdp_media_profiles_t *profile_p;
1725 : char tmp[SDP_MAX_STRING_LEN];
1726 : char *tmp2;
1727 :
1728 : /* If the transport type is any of the AAL2 formats, then we
1729 : * need to look for multiple AAL2 profiles and their associated
1730 : * payload lists. */
1731 0 : mca_p->media_profiles_p = (sdp_media_profiles_t *) \
1732 0 : SDP_MALLOC(sizeof(sdp_media_profiles_t));
1733 0 : if (mca_p->media_profiles_p == NULL) {
1734 0 : sdp_p->conf_p->num_no_resource++;
1735 0 : SDP_FREE(mca_p);
1736 0 : return (SDP_NO_RESOURCE);
1737 : }
1738 0 : profile_p = mca_p->media_profiles_p;
1739 : /* Set the first profile to the one already detected. */
1740 0 : profile_p->num_profiles = 1;
1741 0 : prof = 0;
1742 0 : payload = 0;
1743 0 : profile_p->profile[prof] = mca_p->transport;
1744 0 : profile_p->num_payloads[prof] = 0;
1745 :
1746 : /* Now find the payload type lists and any other profile types */
1747 : while (TRUE) {
1748 0 : ptr = sdp_getnextstrtok(ptr, tmp, sizeof(tmp), " \t", &result);
1749 0 : if (result != SDP_SUCCESS) {
1750 : /* If there are no more payload types, we're finished */
1751 0 : break;
1752 : }
1753 :
1754 : /* See if the next token is a new profile type. */
1755 0 : if (prof < SDP_MAX_PROFILES) {
1756 0 : profile_p->profile[prof+1] = SDP_TRANSPORT_UNSUPPORTED;
1757 0 : for (i=SDP_TRANSPORT_AAL2_ITU;
1758 0 : i <= SDP_TRANSPORT_AAL2_CUSTOM; i++) {
1759 0 : if (cpr_strncasecmp(tmp, sdp_transport[i].name,
1760 0 : sdp_transport[i].strlen) == 0) {
1761 0 : profile_p->profile[prof+1] = (sdp_transport_e)i;
1762 0 : break;
1763 : }
1764 : }
1765 : /* If we recognized the profile type, start looking for the
1766 : * next payload list. */
1767 0 : if (profile_p->profile[prof+1] != SDP_TRANSPORT_UNSUPPORTED) {
1768 : /* Now reset the payload counter for the next profile type. */
1769 0 : payload = 0;
1770 0 : prof++;
1771 0 : profile_p->num_profiles++;
1772 0 : if (prof < SDP_MAX_PROFILES) {
1773 0 : profile_p->num_payloads[prof] = 0;
1774 : }
1775 0 : continue;
1776 : }
1777 : }
1778 :
1779 : /* This token must be a payload type. Make sure there aren't
1780 : * too many payload types. */
1781 0 : if (payload >= SDP_MAX_PAYLOAD_TYPES) {
1782 0 : sdp_parse_error(sdp_p,
1783 : "%s Warning: Too many payload types "
1784 0 : "found, truncating.", sdp_p->debug_str);
1785 0 : continue;
1786 : }
1787 :
1788 : /* See if the payload type is numeric. */
1789 0 : if (prof < SDP_MAX_PROFILES && payload < SDP_MAX_PAYLOAD_TYPES) {
1790 0 : profile_p->payload_type[prof][payload] = (uint16_t)sdp_getnextnumtok(tmp,
1791 : (const char **)&tmp2,
1792 : " \t", &result);
1793 0 : if (result == SDP_SUCCESS) {
1794 0 : profile_p->payload_indicator[prof][payload] = SDP_PAYLOAD_NUMERIC;
1795 0 : profile_p->num_payloads[prof]++;
1796 0 : payload++;
1797 0 : continue;
1798 : }
1799 : }
1800 :
1801 : /* No string payload types are currently valid for the AAL2
1802 : * transport types. This support can be added when needed. */
1803 0 : sdp_parse_error(sdp_p,
1804 : "%s Warning: Unsupported payload type "
1805 0 : "found (%s).", sdp_p->debug_str, tmp);
1806 : }
1807 0 : for (i=0; i < profile_p->num_profiles; i++) {
1808 : /* Make sure we have payloads for each profile type. */
1809 0 : if (profile_p->num_payloads[i] == 0) {
1810 0 : sdp_parse_error(sdp_p,
1811 : "%s Warning: No payload types specified "
1812 0 : "for AAL2 profile %s.", sdp_p->debug_str,
1813 : sdp_get_transport_name(profile_p->profile[i]));
1814 : }
1815 : }
1816 0 : return (SDP_SUCCESS);
1817 : }
|