4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Parses the SDP description as per the SDP grammar defined in Section 9 of
40 #include "sdp_parse.h"
41 #include "commp_util.h"
44 * proto-version-field (v=)
45 * %x76 "=" 1*DIGIT CRLF
48 sdp_parse_version(int *version
, const char *begin
, const char *end
,
51 if (*begin
++ != COMMP_EQUALS
|| commp_atoi(begin
, end
, version
) != 0)
52 *p_error
|= SDP_VERSION_ERROR
;
56 * session-name-field (s=)
59 * byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
60 * ;any byte except NUL, CR, or LF
63 sdp_parse_name(char **name
, const char *begin
, const char *end
,
68 if (*begin
++ != COMMP_EQUALS
) {
69 *p_error
|= SDP_NAME_ERROR
;
72 /* there can be only one name field */
77 *p_error
|= SDP_NAME_ERROR
;
79 COMMP_COPY_STR(*name
, begin
, len
);
81 *p_error
|= SDP_MEMORY_ERROR
;
88 * information-field (i=)
89 * [%x69 "=" text CRLF]
91 * byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
92 * any byte except NUL, CR, or LF
95 sdp_parse_info(char **info
, const char *begin
, const char *end
,
100 if (*begin
++ != COMMP_EQUALS
) {
101 *p_error
|= SDP_INFO_ERROR
;
104 /* There can be only one info field */
109 *p_error
|= SDP_INFO_ERROR
;
111 COMMP_COPY_STR(*info
, begin
, len
);
113 *p_error
|= SDP_MEMORY_ERROR
;
121 * [%x75 "=" uri CRLF]
122 * anything between "=" and "CRLF" is considered to be URI.
125 sdp_parse_uri(char **uri
, const char *begin
, const char *end
, uint_t
*p_error
)
129 if (*begin
++ != COMMP_EQUALS
) {
130 *p_error
|= SDP_URI_ERROR
;
133 /* There can be only one uri field */
137 if (len
< 1 || isspace(*begin
) || isspace (*(end
- 1))) {
138 *p_error
|= SDP_URI_ERROR
;
140 COMMP_COPY_STR(*uri
, begin
, len
);
142 *p_error
|= SDP_MEMORY_ERROR
;
150 * *(%x70 "=" phone-number CRLF)
151 * anything between "=" and "CRLF" is considered to be phone-number
154 sdp_parse_phone(sdp_list_t
**phone
, const char *begin
, const char *end
,
158 sdp_list_t
*new_phone
= NULL
;
159 sdp_list_t
*tmp
= NULL
;
161 if (*begin
++ != COMMP_EQUALS
) {
162 *p_error
|= SDP_PHONE_ERROR
;
166 if (len
< 1 || isspace(*begin
) || isspace(*(end
- 1))) {
167 *p_error
|= SDP_PHONE_ERROR
;
169 new_phone
= calloc(1, sizeof (sdp_list_t
));
170 if (new_phone
== NULL
) {
171 *p_error
|= SDP_MEMORY_ERROR
;
174 COMMP_COPY_STR(new_phone
->value
, begin
, len
);
175 if (new_phone
->value
== NULL
) {
177 *p_error
|= SDP_MEMORY_ERROR
;
180 if (*phone
== NULL
) {
184 while (tmp
->next
!= NULL
)
186 tmp
->next
= new_phone
;
193 * *(%x65 "=" email-address CRLF)
194 * anything between "=" and "CRLF" is considered to be email-address
197 sdp_parse_email(sdp_list_t
**email
, const char *begin
, const char *end
,
201 sdp_list_t
*new_email
= NULL
;
202 sdp_list_t
*tmp
= NULL
;
204 if (*begin
++ != COMMP_EQUALS
) {
205 *p_error
|= SDP_EMAIL_ERROR
;
209 if (len
< 1 || isspace(*begin
) || isspace(*(end
- 1))) {
210 *p_error
|= SDP_EMAIL_ERROR
;
212 new_email
= calloc(1, sizeof (sdp_list_t
));
213 if (new_email
== NULL
) {
214 *p_error
|= SDP_MEMORY_ERROR
;
217 COMMP_COPY_STR(new_email
->value
, begin
, len
);
218 if (new_email
->value
== NULL
) {
220 *p_error
|= SDP_MEMORY_ERROR
;
223 if (*email
== NULL
) {
227 while (tmp
->next
!= NULL
)
229 tmp
->next
= new_email
;
236 * %x6f "=" username SP sess-id SP sess-version SP nettype SP addrtype SP
237 * unicast-address CRLF
239 * username = non-ws-string
241 * sess-version = 1*DIGIT
244 * token = 1*(token-char)
245 * token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
246 * i.e. no space in token-char
249 sdp_parse_origin(sdp_origin_t
**origin
, const char *begin
, const char *end
,
252 const char *current
= NULL
;
253 sdp_origin_t
*new_origin
= NULL
;
255 if (*begin
++ != COMMP_EQUALS
) {
256 *p_error
|= SDP_ORIGIN_ERROR
;
259 /* There can be only one origin field */
262 new_origin
= calloc(1, sizeof (sdp_origin_t
));
263 if (new_origin
== NULL
) {
264 *p_error
|= SDP_MEMORY_ERROR
;
269 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
272 COMMP_COPY_STR(new_origin
->o_username
, begin
, current
- begin
);
273 if (new_origin
->o_username
== NULL
) {
274 sdp_free_origin(new_origin
);
275 *p_error
|= SDP_MEMORY_ERROR
;
281 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
283 if (commp_strtoull(begin
, current
, &new_origin
->o_id
) != 0)
287 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
289 if (commp_strtoull(begin
, current
, &new_origin
->o_version
) != 0)
293 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
296 COMMP_COPY_STR(new_origin
->o_nettype
, begin
, current
- begin
);
297 if (new_origin
->o_nettype
== NULL
) {
298 sdp_free_origin(new_origin
);
299 *p_error
|= SDP_MEMORY_ERROR
;
305 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
308 COMMP_COPY_STR(new_origin
->o_addrtype
, begin
, current
- begin
);
309 if (new_origin
->o_addrtype
== NULL
) {
310 sdp_free_origin(new_origin
);
311 *p_error
|= SDP_MEMORY_ERROR
;
315 /* Get address. Its the last sub-field */
317 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_TRUE
) != 0)
319 COMMP_COPY_STR(new_origin
->o_address
, begin
, current
- begin
);
320 if (new_origin
->o_address
== NULL
) {
321 sdp_free_origin(new_origin
);
322 *p_error
|= SDP_MEMORY_ERROR
;
325 *origin
= new_origin
;
328 *p_error
|= SDP_ORIGIN_ERROR
;
329 sdp_free_origin(new_origin
);
334 * 1*( %x74 "=" start-time SP stop-time CRLF)
335 * start-time = time / "0"
336 * stop-time = time / "0"
337 * time = POS-DIGIT 9*DIGIT
338 * POS-DIGIT = %x31-39 ; 1 - 9
341 sdp_parse_time(sdp_time_t
**time
, const char *begin
, const char *end
,
345 sdp_time_t
*new_time
;
348 if (*begin
++ != COMMP_EQUALS
) {
349 *p_error
|= SDP_TIME_ERROR
;
352 new_time
= calloc(1, sizeof (sdp_time_t
));
353 if (new_time
== NULL
) {
354 *p_error
|= SDP_MEMORY_ERROR
;
359 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
361 if (commp_strtoull(begin
, current
, &new_time
->t_start
) != 0)
365 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_TRUE
) != 0)
367 if (commp_strtoull(begin
, current
, &new_time
->t_stop
) != 0)
369 /* Now assign time to session structure */
374 while (tmp
->t_next
!= NULL
)
376 tmp
->t_next
= new_time
;
380 *p_error
|= SDP_TIME_ERROR
;
381 sdp_free_time(new_time
);
386 * connection-field (c=)
387 * [%x63 "=" nettype SP addrtype SP connection-address CRLF]
390 * connection-address = multicast-address / unicast-address
391 * here, connection-address is parsed as a string.
394 sdp_parse_connection(sdp_conn_t
**conn
, const char *begin
, const char *end
,
399 const char *t_current
;
400 sdp_conn_t
*new_conn
;
402 boolean_t is_IP4
= B_FALSE
;
403 boolean_t is_IP6
= B_FALSE
;
405 if (*begin
++ != COMMP_EQUALS
) {
406 *p_error
|= SDP_CONNECTION_ERROR
;
409 new_conn
= calloc(1, sizeof (sdp_conn_t
));
410 if (new_conn
== NULL
) {
411 *p_error
|= SDP_MEMORY_ERROR
;
414 /* Get NetworkType */
416 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
419 COMMP_COPY_STR(new_conn
->c_nettype
, begin
, current
- begin
);
420 if (new_conn
->c_nettype
== NULL
) {
421 sdp_free_connection(new_conn
);
422 *p_error
|= SDP_MEMORY_ERROR
;
426 /* Get AddressType */
428 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
431 COMMP_COPY_STR(new_conn
->c_addrtype
, begin
, current
- begin
);
432 if (new_conn
->c_addrtype
== NULL
) {
433 sdp_free_connection(new_conn
);
434 *p_error
|= SDP_MEMORY_ERROR
;
438 if ((strlen(COMMP_ADDRTYPE_IP4
) == strlen(new_conn
->c_addrtype
)) &&
439 (strncasecmp(new_conn
->c_addrtype
, COMMP_ADDRTYPE_IP4
,
440 strlen(COMMP_ADDRTYPE_IP4
)) == 0)) {
442 } else if ((strlen(COMMP_ADDRTYPE_IP6
) == strlen(new_conn
->
443 c_addrtype
)) && (strncasecmp(new_conn
->c_addrtype
,
444 COMMP_ADDRTYPE_IP6
, strlen(COMMP_ADDRTYPE_IP6
)) == 0)) {
447 /* Get Address. Parsing depends if its IP4,IP6 or something else */
449 if (!is_IP4
&& !is_IP6
) {
450 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
,
455 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SLASH
,
459 if (current
!= end
) {
460 /* SLASH is present. Needs further parsing */
462 t_begin
= ++t_current
;
463 if (commp_find_token(&t_begin
, &t_current
, end
,
464 COMMP_SLASH
, B_FALSE
) != 0) {
467 if (t_current
!= end
) {
469 * Another SLASH present. If is_IP4 true then
470 * this is Address count. If is_IP6 true then
471 * incorrect field as per RFC.
476 if (commp_atoi((t_current
+ 1), end
,
477 &new_conn
->c_addrcount
) != 0) {
483 if (commp_atoi((current
+ 1), t_current
,
484 &new_conn
->c_addrcount
) != 0) {
488 if (commp_strtoub((current
+ 1), t_current
,
489 &new_conn
->c_ttl
) != 0) {
492 if (new_conn
->c_addrcount
== 0)
493 new_conn
->c_addrcount
= 1;
497 COMMP_COPY_STR(new_conn
->c_address
, begin
, current
- begin
);
498 if (new_conn
->c_address
== NULL
) {
499 sdp_free_connection(new_conn
);
500 *p_error
|= SDP_MEMORY_ERROR
;
507 while (tmp
->c_next
!= NULL
)
509 tmp
->c_next
= new_conn
;
513 *p_error
|= SDP_CONNECTION_ERROR
;
514 sdp_free_connection(new_conn
);
518 * bandwidth-fields (b=)
519 * *(%x62 "=" bwtype ":" bandwidth CRLF)
521 * bandwidth = 1*DIGIT
524 sdp_parse_bandwidth(sdp_bandwidth_t
**bw
, const char *begin
, const char *end
,
528 sdp_bandwidth_t
*new_bw
= NULL
;
529 sdp_bandwidth_t
*tmp
= NULL
;
531 if (*begin
++ != COMMP_EQUALS
) {
532 *p_error
|= SDP_BANDWIDTH_ERROR
;
535 new_bw
= calloc(1, sizeof (sdp_bandwidth_t
));
536 if (new_bw
== NULL
) {
537 *p_error
|= SDP_MEMORY_ERROR
;
541 if (commp_find_token(&begin
, ¤t
, end
, COMMP_COLON
,
545 COMMP_COPY_STR(new_bw
->b_type
, begin
, current
- begin
);
546 if (new_bw
->b_type
== NULL
) {
547 sdp_free_bandwidth(new_bw
);
548 *p_error
|= SDP_MEMORY_ERROR
;
555 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_TRUE
) != 0)
557 if (commp_strtoull(begin
, current
, &new_bw
->b_value
) != 0)
563 while (tmp
->b_next
!= NULL
)
565 tmp
->b_next
= new_bw
;
569 *p_error
|= SDP_BANDWIDTH_ERROR
;
570 sdp_free_bandwidth(new_bw
);
575 * Not stand-alone. One or more repeat field appear after time field.
576 * %x72 "=" repeat-interval SP typed-time 1*(SP typed-time)
577 * repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
578 * typed-time = 1*DIGIT [fixed-len-time-unit]
579 * fixed-len-time-unit = %x64 / %x68 / %x6d / %x73
582 sdp_parse_repeat(sdp_time_t
*time
, const char *begin
, const char *end
,
586 sdp_repeat_t
*repeat
;
587 sdp_repeat_t
*new_repeat
;
590 if (*begin
++ != COMMP_EQUALS
) {
591 *p_error
|= SDP_REPEAT_TIME_ERROR
;
595 * A time field should be present before this field can occur, if
596 * time is NULL then repeat field has occured before time field and
597 * hence fields are out of order.
602 * Get the latest time field and associate this repeat field
605 while (time
->t_next
!= NULL
)
607 new_repeat
= calloc(1, sizeof (sdp_repeat_t
));
608 if (new_repeat
== NULL
) {
609 *p_error
|= SDP_MEMORY_ERROR
;
613 * for a given time field, there could be several repeat fields
614 * add the new repeat field at the end of it.
616 repeat
= time
->t_repeat
;
617 if (repeat
== NULL
) {
618 time
->t_repeat
= new_repeat
;
620 while (repeat
->r_next
!= NULL
)
621 repeat
= repeat
->r_next
;
622 repeat
->r_next
= new_repeat
;
625 * Populate the elements of sdp_repeat.
629 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
631 if (commp_time_to_secs(begin
, current
, &new_repeat
->r_interval
) != 0)
633 /* Get duration. It could be the last sub-field */
635 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
637 if (commp_time_to_secs(begin
, current
, &new_repeat
->r_duration
) != 0)
640 /* Get offsets into sdp_list */
643 while (current
< end
) {
645 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
,
649 if ((ret
= add_value_to_list(&new_repeat
->r_offset
, begin
,
650 current
- begin
, B_FALSE
)) != 0) {
652 *p_error
|= SDP_MEMORY_ERROR
;
660 /* check for trailing white space character. */
661 if (isspace(*(end
- 1)))
665 *p_error
|= SDP_REPEAT_TIME_ERROR
;
667 repeat
->r_next
= NULL
;
669 time
->t_repeat
= NULL
;
670 sdp_free_repeat(new_repeat
);
674 * zone-adjustments (z=)
675 * %x7a "=" time SP ["-"] typed-time *(SP time SP ["-"] typed-time)
678 sdp_parse_zone(sdp_zone_t
**zone
, const char *begin
, const char *end
,
682 sdp_zone_t
*new_zone
= NULL
;
683 sdp_zone_t
*tmp
= NULL
;
685 if (*begin
++ != COMMP_EQUALS
) {
686 *p_error
|= SDP_ZONE_ERROR
;
689 /* There can be atmost one zone field. */
692 /* Get time and offset */
694 while (current
< end
) {
695 new_zone
= calloc(1, sizeof (sdp_zone_t
));
696 if (new_zone
== NULL
) {
697 *p_error
|= SDP_MEMORY_ERROR
;
704 tmp
->z_next
= new_zone
;
708 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
,
712 if (commp_strtoull(begin
, current
, &new_zone
->z_time
) != 0)
715 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
,
719 COMMP_COPY_STR(new_zone
->z_offset
, begin
, current
-
721 if (new_zone
->z_offset
== NULL
) {
722 *p_error
|= SDP_MEMORY_ERROR
;
729 if (isspace(*(end
- 1)))
733 *p_error
|= SDP_ZONE_ERROR
;
734 sdp_free_zone(*zone
);
740 * [%x6b "=" key-type CRLF]
741 * key-type = %x70 %x72 %x6f %x6d %x70 %x74 / ; "prompt"
742 * %x63 %x6c %x65 %x61 %x72 ":" text / ; "clear:"
743 * %x62 %x61 %x73 %x65 "64:" base64 / ; "base64:"
744 * %x75 %x72 %x69 ":" uri ; "uri:"
747 sdp_parse_key(sdp_key_t
**key
, const char *begin
, const char *end
,
753 if (*begin
++ != COMMP_EQUALS
) {
754 *p_error
|= SDP_KEY_ERROR
;
757 /* There can be only one key field */
760 new_key
= calloc(1, sizeof (sdp_key_t
));
761 if (new_key
== NULL
) {
762 *p_error
|= SDP_MEMORY_ERROR
;
765 /* Get Method name */
767 if (commp_find_token(&begin
, ¤t
, end
, COMMP_COLON
,
771 COMMP_COPY_STR(new_key
->k_method
, begin
, current
- begin
);
772 if (new_key
->k_method
== NULL
) {
773 sdp_free_key(new_key
);
774 *p_error
|= SDP_MEMORY_ERROR
;
778 /* Get key, if exists. */
779 if (*current
== COMMP_COLON
) {
783 COMMP_COPY_STR(new_key
->k_enckey
, current
, end
- current
);
784 if (new_key
->k_enckey
== NULL
) {
785 sdp_free_key(new_key
);
786 *p_error
|= SDP_MEMORY_ERROR
;
793 *p_error
|= SDP_KEY_ERROR
;
794 sdp_free_key(new_key
);
798 * attribute-fields (a=)
799 * *(%x61 "=" attribute CRLF)
800 * attribute = (att-field ":" att-value) / att-field
802 * att-value = byte-string
805 sdp_parse_attribute(sdp_attr_t
**attr
, const char *begin
, const char *end
,
809 sdp_attr_t
*new_attr
;
812 if (*begin
++ != COMMP_EQUALS
) {
813 *p_error
|= SDP_ATTRIBUTE_ERROR
;
816 new_attr
= calloc(1, sizeof (sdp_attr_t
));
817 if (new_attr
== NULL
) {
818 *p_error
|= SDP_MEMORY_ERROR
;
821 /* Get Attribute Name */
823 if (commp_find_token(&begin
, ¤t
, end
, COMMP_COLON
,
827 COMMP_COPY_STR(new_attr
->a_name
, begin
, current
- begin
);
828 if (new_attr
->a_name
== NULL
) {
829 sdp_free_attribute(new_attr
);
830 *p_error
|= SDP_MEMORY_ERROR
;
834 /* Get Attribute Value */
835 if (*current
== COMMP_COLON
) {
839 COMMP_COPY_STR(new_attr
->a_value
, current
, end
- current
);
840 if (new_attr
->a_value
== NULL
) {
841 sdp_free_attribute(new_attr
);
842 *p_error
|= SDP_MEMORY_ERROR
;
850 while (tmp
->a_next
!= NULL
)
852 tmp
->a_next
= new_attr
;
856 *p_error
|= SDP_ATTRIBUTE_ERROR
;
857 sdp_free_attribute(new_attr
);
862 * %x6d "=" media SP port ["/" integer] SP proto 1*(SP fmt) CRLF
865 sdp_parse_media(sdp_session_t
*session
, const char *begin
, const char *end
,
869 const char *fake_end
;
870 sdp_media_t
*new_media
;
873 if (*begin
++ != COMMP_EQUALS
) {
874 *p_error
|= SDP_MEDIA_ERROR
;
878 new_media
= calloc(1, sizeof (sdp_media_t
));
879 if (new_media
== NULL
) {
880 *p_error
|= SDP_MEMORY_ERROR
;
883 new_media
->m_session
= session
;
886 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
889 COMMP_COPY_STR(new_media
->m_name
, begin
, current
- begin
);
890 if (new_media
->m_name
== NULL
) {
891 sdp_free_media(new_media
);
892 *p_error
|= SDP_MEMORY_ERROR
;
898 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0)
902 if (commp_find_token(&begin
, ¤t
, fake_end
, COMMP_SLASH
,
906 if (commp_atoui(begin
, current
, &new_media
->m_port
) != 0)
909 if (*current
== COMMP_SLASH
) {
911 if (commp_find_token(&begin
, ¤t
, fake_end
, COMMP_SP
,
915 if (commp_atoi(begin
, current
, &new_media
->m_portcount
) != 0)
918 new_media
->m_portcount
= 1;
922 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
, B_FALSE
) != 0) {
925 COMMP_COPY_STR(new_media
->m_proto
, begin
, current
- begin
);
926 if (new_media
->m_proto
== NULL
) {
927 sdp_free_media(new_media
);
928 *p_error
|= SDP_MEMORY_ERROR
;
933 /* Get format list */
936 while (current
< end
) {
938 if (commp_find_token(&begin
, ¤t
, end
, COMMP_SP
,
942 if (add_value_to_list(&new_media
->m_format
, begin
,
943 current
- begin
, B_TRUE
) != 0) {
944 sdp_free_media(new_media
);
945 *p_error
|= SDP_MEMORY_ERROR
;
950 /* check for trailing white space character. */
951 if (isspace(*(end
- 1)))
953 /* Assign new media to the media list */
954 tmp
= session
->s_media
;
956 session
->s_media
= new_media
;
958 while (tmp
->m_next
!= NULL
)
960 tmp
->m_next
= new_media
;
964 *p_error
|= SDP_MEDIA_ERROR
;
965 sdp_free_media(new_media
);
970 * This function ensures that a field is in the right order in SDP descripton.
971 * It also identifies cases where a field ('v', 'o, 'i', et al) that must occur
972 * once but occurs several times in SDP description. error cannot be NULL.
975 sdp_check_order(char prev
, char *order
, int *error
)
978 while (*order
!= '\0') {
979 if (*order
++ == prev
)
986 * This function determines the SDP field and calls the appropriate parse
987 * function. It also ensures that the SDP fields are in strict order.
990 sdp_handle_fields(sdp_description_t
*description
, sdp_session_t
*_session
,
991 const char *begin
, const char *end
)
993 boolean_t u_field
= B_FALSE
;
994 int error
= 0; /* fields order error */
995 char prev
= description
->d_prev
;
996 char m_prev
= description
->d_mprev
;
999 case SDP_VERSION_FIELD
:
1000 sdp_check_order(prev
, SDP_VERSION_ORDER
, &error
);
1001 description
->d_version
= B_TRUE
;
1002 sdp_parse_version(&_session
->s_version
, begin
+ 1, end
,
1003 &description
->d_perror
);
1005 case SDP_ORIGIN_FIELD
:
1006 sdp_check_order(prev
, SDP_ORIGIN_ORDER
, &error
);
1007 description
->d_origin
= B_TRUE
;
1008 sdp_parse_origin(&_session
->s_origin
, begin
+ 1, end
,
1009 &description
->d_perror
);
1011 case SDP_NAME_FIELD
:
1012 sdp_check_order(prev
, SDP_NAME_ORDER
, &error
);
1013 description
->d_name
= B_TRUE
;
1014 sdp_parse_name(&_session
->s_name
, begin
+ 1, end
,
1015 &description
->d_perror
);
1017 case SDP_INFO_FIELD
:
1018 if (description
->d_mparsed
) {
1019 sdp_check_order(m_prev
, SDP_M_INFO_ORDER
,
1021 if (description
->d_lmedia
== NULL
)
1023 sdp_parse_info(&(description
->d_lmedia
->
1024 m_info
), begin
+ 1, end
, &description
->
1027 sdp_check_order(prev
, SDP_INFO_ORDER
, &error
);
1028 sdp_parse_info(&_session
->s_info
, begin
+ 1,
1029 end
, &description
->d_perror
);
1033 sdp_check_order(prev
, SDP_URI_ORDER
, &error
);
1034 sdp_parse_uri(&_session
->s_uri
, begin
+ 1, end
,
1035 &description
->d_perror
);
1037 case SDP_EMAIL_FIELD
:
1038 sdp_check_order(prev
, SDP_EMAIL_ORDER
, &error
);
1039 sdp_parse_email(&_session
->s_email
, begin
+ 1, end
,
1040 &description
->d_perror
);
1042 case SDP_PHONE_FIELD
:
1043 sdp_check_order(prev
, SDP_PHONE_ORDER
, &error
);
1044 sdp_parse_phone(&_session
->s_phone
, begin
+ 1, end
,
1045 &description
->d_perror
);
1047 case SDP_CONNECTION_FIELD
:
1048 if (description
->d_mparsed
) {
1049 sdp_check_order(m_prev
, SDP_M_CONN_ORDER
,
1051 --description
->d_mccount
;
1052 if (description
->d_lmedia
== NULL
)
1054 sdp_parse_connection(&(description
->d_lmedia
->
1055 m_conn
), begin
+ 1, end
,
1056 &description
->d_perror
);
1059 * RFC - 4566 says that session section should
1060 * have only one connection field, while media
1061 * section can have many
1063 sdp_check_order(prev
, SDP_CONN_ORDER
, &error
);
1064 description
->d_conn
= B_TRUE
;
1065 if (_session
->s_conn
!= NULL
)
1067 sdp_parse_connection(&_session
->s_conn
,
1068 begin
+ 1, end
, &description
->d_perror
);
1071 case SDP_BANDWIDTH_FIELD
:
1072 if (description
->d_mparsed
) {
1073 sdp_check_order(m_prev
, SDP_M_BW_ORDER
, &error
);
1074 if (description
->d_lmedia
== NULL
)
1076 sdp_parse_bandwidth(&(description
->d_lmedia
->
1077 m_bw
), begin
+ 1, end
,
1078 &description
->d_perror
);
1080 sdp_check_order(prev
, SDP_BW_ORDER
, &error
);
1081 sdp_parse_bandwidth(&_session
->s_bw
,
1082 begin
+ 1, end
, &description
->d_perror
);
1085 case SDP_TIME_FIELD
:
1086 if (!description
->d_tparsed
|| description
->d_prev
!=
1088 sdp_check_order(prev
, SDP_TIME_ORDER
, &error
);
1090 description
->d_tparsed
= B_TRUE
;
1091 description
->d_ltime
= sdp_parse_time(&_session
->
1092 s_time
, begin
+ 1, end
, &description
->d_perror
);
1094 case SDP_REPEAT_FIELD
:
1095 sdp_check_order(prev
, SDP_REPEAT_ORDER
, &error
);
1096 if (description
->d_ltime
== NULL
)
1098 /* we pass time, as repeat is associated with time */
1099 sdp_parse_repeat(description
->d_ltime
, begin
+ 1, end
,
1100 &description
->d_perror
);
1102 case SDP_ZONE_FIELD
:
1103 sdp_check_order(prev
, SDP_ZONE_ORDER
, &error
);
1104 sdp_parse_zone(&_session
->s_zone
, begin
+ 1, end
,
1105 &description
->d_perror
);
1108 if (description
->d_mparsed
) {
1109 sdp_check_order(m_prev
, SDP_M_KEY_ORDER
,
1111 if (description
->d_lmedia
== NULL
)
1113 sdp_parse_key(&(description
->d_lmedia
->m_key
),
1114 begin
+ 1, end
, &description
->d_perror
);
1116 sdp_check_order(prev
, SDP_KEY_ORDER
, &error
);
1117 sdp_parse_key(&_session
->s_key
, begin
+ 1, end
,
1118 &description
->d_perror
);
1121 case SDP_ATTRIBUTE_FIELD
:
1122 if (description
->d_mparsed
) {
1123 sdp_check_order(m_prev
, SDP_M_ATTR_ORDER
,
1125 if (description
->d_lmedia
== NULL
)
1127 sdp_parse_attribute(&(description
->d_lmedia
->
1128 m_attr
), begin
+ 1, end
,
1129 &description
->d_perror
);
1131 sdp_check_order(prev
, SDP_ATTR_ORDER
, &error
);
1132 sdp_parse_attribute(&_session
->s_attr
,
1133 begin
+ 1, end
, &description
->d_perror
);
1136 case SDP_MEDIA_FIELD
:
1137 if (!description
->d_mparsed
) {
1138 sdp_check_order(prev
, SDP_MEDIA_ORDER
, &error
);
1139 description
->d_mccount
= 1;
1141 if (description
->d_mccount
== 1)
1142 description
->d_mconn
= B_FALSE
;
1143 description
->d_mccount
= 1;
1145 description
->d_mparsed
= B_TRUE
;
1146 description
->d_lmedia
= sdp_parse_media(_session
,
1147 begin
+ 1, end
, &description
->d_perror
);
1150 /* Unknown field type. Ignore it */
1155 description
->d_perror
|= SDP_FIELDS_ORDER_ERROR
;
1157 if (!description
->d_mparsed
)
1158 description
->d_prev
= *begin
;
1160 description
->d_mprev
= *begin
;
1165 * Parses the SDP info
1168 sdp_parse(const char *sdp_info
, int len
, int flags
, sdp_session_t
**session
,
1172 const char *f_begin
;
1174 sdp_description_t
*description
;
1177 const char *current
;
1179 if (sdp_info
== NULL
|| len
== 0 || p_error
== NULL
|| flags
!= 0 ||
1181 if (session
!= NULL
)
1187 description
= calloc(1, sizeof (sdp_description_t
));
1188 if (description
== NULL
) {
1191 /* Needed later to check for mandatory fields */
1192 description
->d_prev
= COMMP_SP
;
1193 description
->d_mconn
= B_TRUE
;
1194 *session
= sdp_new_session();
1195 if (*session
== NULL
) {
1201 if (commp_skip_white_space(&start
, end
) != 0) {
1209 while ((current
< end
) && !(description
->d_perror
&
1210 SDP_MEMORY_ERROR
)) {
1212 * RFC says parser SHOULD be tolerant to records ending
1213 * with a single newline character too.
1215 if (strncmp(COMMP_CRLF
, current
, strlen(COMMP_CRLF
)) == 0) {
1217 sdp_handle_fields(description
, *session
, f_begin
,
1219 COMMP_SKIP_CRLF(current
);
1220 (void) commp_skip_white_space(¤t
, end
);
1222 } else if (strncmp(COMMP_LF
, current
, strlen(COMMP_LF
)) == 0) {
1224 sdp_handle_fields(description
, *session
, f_begin
,
1226 COMMP_SKIP_LF(current
);
1227 (void) commp_skip_white_space(¤t
, end
);
1233 if (description
->d_perror
& SDP_MEMORY_ERROR
) {
1235 sdp_free_session(*session
);
1240 * Check for mandatory fields v, o, s, t fields. For connection field,
1241 * RFC says; a connection field must be present in every media
1242 * description or at the session-level
1244 if (description
->d_mccount
== 1)
1245 description
->d_mconn
= B_FALSE
;
1246 if (!(description
->d_version
&& description
->d_origin
&&
1247 description
->d_name
&& description
->d_tparsed
&&
1248 (description
->d_conn
|| (description
->d_mparsed
&&
1249 description
->d_mconn
)))) {
1250 description
->d_perror
|= SDP_MISSING_FIELDS
;
1252 *p_error
= description
->d_perror
;