/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Parses the SDP description as per the SDP grammar defined in Section 9 of
* RFC 4566
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sdp.h>
#include "sdp_parse.h"
#include "commp_util.h"
/*
* proto-version-field (v=)
* %x76 "=" 1*DIGIT CRLF
*/
static void
{
*p_error |= SDP_VERSION_ERROR;
}
/*
* session-name-field (s=)
* %x73 "=" text CRLF
* text = byte-string
* byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
* ;any byte except NUL, CR, or LF
*/
static void
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_NAME_ERROR;
return;
}
/* there can be only one name field */
return;
if (len < 1) {
*p_error |= SDP_NAME_ERROR;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
/*
* information-field (i=)
* [%x69 "=" text CRLF]
* text = byte-string
* byte-string = 1*(%x01-09/%x0B-0C/%x0E-FF)
* any byte except NUL, CR, or LF
*/
static void
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_INFO_ERROR;
return;
}
/* There can be only one info field */
return;
if (len < 1) {
*p_error |= SDP_INFO_ERROR;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
/*
* uri-field (u=)
* [%x75 "=" uri CRLF]
* anything between "=" and "CRLF" is considered to be URI.
*/
static void
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_URI_ERROR;
return;
}
/* There can be only one uri field */
return;
*p_error |= SDP_URI_ERROR;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
/*
* phone-fields (p=)
* *(%x70 "=" phone-number CRLF)
* anything between "=" and "CRLF" is considered to be phone-number
*/
static void
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_PHONE_ERROR;
return;
}
*p_error |= SDP_PHONE_ERROR;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
} else {
}
}
}
/*
* email-fields (e=)
* *(%x65 "=" email-address CRLF)
* anything between "=" and "CRLF" is considered to be email-address
*/
static void
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_EMAIL_ERROR;
return;
}
*p_error |= SDP_EMAIL_ERROR;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
} else {
}
}
}
/*
* origin-field (o=)
* %x6f "=" username SP sess-id SP sess-version SP nettype SP addrtype SP
* unicast-address CRLF
*
* username = non-ws-string
* sess-id = 1*DIGIT
* sess-version = 1*DIGIT
* nettype = token
* addrtype = token
* token = 1*(token-char)
* token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
* i.e. no space in token-char
*/
static void
{
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_ORIGIN_ERROR;
return;
}
/* There can be only one origin field */
return;
if (new_origin == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
/* Get username */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get Session-ID */
goto err_ret;
goto err_ret;
/* Get Version */
goto err_ret;
goto err_ret;
/* Get nettype */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get addrtype */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get address. Its the last sub-field */
goto err_ret;
*p_error |= SDP_MEMORY_ERROR;
return;
}
*origin = new_origin;
return;
*p_error |= SDP_ORIGIN_ERROR;
}
/*
* time-fields (t=)
* 1*( %x74 "=" start-time SP stop-time CRLF)
* start-time = time / "0"
* stop-time = time / "0"
* time = POS-DIGIT 9*DIGIT
* POS-DIGIT = %x31-39 ; 1 - 9
*/
static sdp_time_t *
{
const char *current;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_TIME_ERROR;
return (NULL);
}
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
/* Get start-time */
goto err_ret;
goto err_ret;
/* Get stop-time */
goto err_ret;
goto err_ret;
/* Now assign time to session structure */
} else {
}
return (new_time);
*p_error |= SDP_TIME_ERROR;
return (NULL);
}
/*
* connection-field (c=)
* [%x63 "=" nettype SP addrtype SP connection-address CRLF]
* nettype = token
* addrtype = token
* connection-address = multicast-address / unicast-address
* here, connection-address is parsed as a string.
*/
static void
{
const char *current;
const char *t_begin;
const char *t_current;
if (*begin++ != COMMP_EQUALS) {
return;
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
/* Get NetworkType */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get AddressType */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
strlen(COMMP_ADDRTYPE_IP4)) == 0)) {
}
/* Get Address. Parsing depends if its IP4,IP6 or something else */
B_TRUE) != 0) {
goto err_ret;
}
} else {
B_FALSE) != 0) {
goto err_ret;
}
/* SLASH is present. Needs further parsing */
COMMP_SLASH, B_FALSE) != 0) {
goto err_ret;
}
/*
* Another SLASH present. If is_IP4 true then
* this is Address count. If is_IP6 true then
* incorrect field as per RFC.
*/
if (is_IP6) {
goto err_ret;
} else {
&new_conn->c_addrcount) != 0) {
goto err_ret;
}
}
}
if (is_IP6) {
&new_conn->c_addrcount) != 0) {
goto err_ret;
}
} else {
goto err_ret;
}
if (new_conn->c_addrcount == 0)
}
}
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
} else {
}
return;
}
/*
* bandwidth-fields (b=)
* *(%x62 "=" bwtype ":" bandwidth CRLF)
* bwtype = token
* bandwidth = 1*DIGIT
*/
static void
{
const char *current;
if (*begin++ != COMMP_EQUALS) {
return;
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
B_FALSE) != 0) {
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
goto err_ret;
goto err_ret;
goto err_ret;
} else {
}
return;
}
/*
* repeat-fields (r=)
* Not stand-alone. One or more repeat field appear after time field.
* %x72 "=" repeat-interval SP typed-time 1*(SP typed-time)
* repeat-interval = POS-DIGIT *DIGIT [fixed-len-time-unit]
* typed-time = 1*DIGIT [fixed-len-time-unit]
* fixed-len-time-unit = %x64 / %x68 / %x6d / %x73
*/
static void
{
const char *current;
int ret;
if (*begin++ != COMMP_EQUALS) {
return;
}
/*
* A time field should be present before this field can occur, if
* time is NULL then repeat field has occured before time field and
* hence fields are out of order.
*/
return;
/*
* Get the latest time field and associate this repeat field
* with it.
*/
if (new_repeat == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
/*
* for a given time field, there could be several repeat fields
* add the new repeat field at the end of it.
*/
} else {
}
/*
* Populate the elements of sdp_repeat.
* Get time-interval
*/
goto err_ret;
goto err_ret;
/* Get duration. It could be the last sub-field */
goto err_ret;
goto err_ret;
++current;
/* Get offsets into sdp_list */
goto err_ret;
B_FALSE) != 0) {
goto err_ret;
}
*p_error |= SDP_MEMORY_ERROR;
return;
} else {
goto err_ret;
}
}
++current;
}
/* check for trailing white space character. */
goto err_ret;
return;
else
}
/*
* zone-adjustments (z=)
* %x7a "=" time SP ["-"] typed-time *(SP time SP ["-"] typed-time)
*/
static void
{
const char *current;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_ZONE_ERROR;
return;
}
/* There can be atmost one zone field. */
return;
/* Get time and offset */
*p_error |= SDP_MEMORY_ERROR;
return;
}
} else {
}
B_FALSE) != 0) {
goto err_ret;
}
goto err_ret;
B_FALSE) != 0) {
goto err_ret;
} else {
begin);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
++current;
}
goto err_ret;
return;
*p_error |= SDP_ZONE_ERROR;
}
/*
* key-field (k=)
* [%x6b "=" key-type CRLF]
* key-type = %x70 %x72 %x6f %x6d %x70 %x74 / ; "prompt"
* %x63 %x6c %x65 %x61 %x72 ":" text / ; "clear:"
* %x62 %x61 %x73 %x65 "64:" base64 / ; "base64:"
* %x75 %x72 %x69 ":" uri ; "uri:"
*/
static void
{
const char *current;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_KEY_ERROR;
return;
}
/* There can be only one key field */
return;
*p_error |= SDP_MEMORY_ERROR;
return;
}
/* Get Method name */
B_FALSE) != 0) {
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get key, if exists. */
if (*current == COMMP_COLON) {
++current;
goto err_ret;
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
return;
*p_error |= SDP_KEY_ERROR;
}
/*
* attribute-fields (a=)
* *(%x61 "=" attribute CRLF)
* attribute = (att-field ":" att-value) / att-field
* att-field = token
* att-value = byte-string
*/
static void
{
const char *current;
if (*begin++ != COMMP_EQUALS) {
return;
}
*p_error |= SDP_MEMORY_ERROR;
return;
}
/* Get Attribute Name */
B_FALSE) != 0) {
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
/* Get Attribute Value */
if (*current == COMMP_COLON) {
++current;
goto err_ret;
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
} else {
}
return;
}
/*
* media-field (m=)
* %x6d "=" media SP port ["/" integer] SP proto 1*(SP fmt) CRLF
*/
static sdp_media_t *
{
const char *current;
const char *fake_end;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_MEDIA_ERROR;
return (NULL);
}
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
/* Get media name */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
}
/* Get port */
goto err_ret;
B_FALSE) != 0) {
goto err_ret;
}
goto err_ret;
/* Get portcount */
if (*current == COMMP_SLASH) {
B_FALSE) != 0) {
goto err_ret;
}
goto err_ret;
} else {
}
/* Get Protocol */
goto err_ret;
} else {
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
}
++current;
/* Get format list */
goto err_ret;
B_FALSE) != 0) {
goto err_ret;
}
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
++current;
}
/* check for trailing white space character. */
goto err_ret;
/* Assign new media to the media list */
} else {
}
return (new_media);
*p_error |= SDP_MEDIA_ERROR;
return (NULL);
}
/*
* This function ensures that a field is in the right order in SDP descripton.
* It also identifies cases where a field ('v', 'o, 'i', et al) that must occur
* once but occurs several times in SDP description. error cannot be NULL.
*/
static void
{
*error = 0;
while (*order != '\0') {
return;
}
*error = 1;
}
/*
* This function determines the SDP field and calls the appropriate parse
* function. It also ensures that the SDP fields are in strict order.
*/
static void
{
switch (*begin) {
case SDP_VERSION_FIELD:
&description->d_perror);
break;
case SDP_ORIGIN_FIELD:
&description->d_perror);
break;
case SDP_NAME_FIELD:
&description->d_perror);
break;
case SDP_INFO_FIELD:
if (description->d_mparsed) {
&error);
break;
d_perror);
} else {
}
break;
case SDP_URI_FIELD:
&description->d_perror);
break;
case SDP_EMAIL_FIELD:
&description->d_perror);
break;
case SDP_PHONE_FIELD:
&description->d_perror);
break;
case SDP_CONNECTION_FIELD:
if (description->d_mparsed) {
&error);
--description->d_mccount;
break;
&description->d_perror);
} else {
/*
* RFC - 4566 says that session section should
* have only one connection field, while media
* section can have many
*/
break;
}
break;
case SDP_BANDWIDTH_FIELD:
if (description->d_mparsed) {
break;
&description->d_perror);
} else {
}
break;
case SDP_TIME_FIELD:
}
break;
case SDP_REPEAT_FIELD:
break;
/* we pass time, as repeat is associated with time */
&description->d_perror);
break;
case SDP_ZONE_FIELD:
&description->d_perror);
break;
case SDP_KEY_FIELD:
if (description->d_mparsed) {
&error);
break;
} else {
&description->d_perror);
}
break;
case SDP_ATTRIBUTE_FIELD:
if (description->d_mparsed) {
&error);
break;
&description->d_perror);
} else {
}
break;
case SDP_MEDIA_FIELD:
if (!description->d_mparsed) {
} else {
}
break;
default:
/* Unknown field type. Ignore it */
break;
}
if (error)
if (!u_field) {
if (!description->d_mparsed)
else
}
}
/*
* Parses the SDP info
*/
int
{
const char *f_begin;
const char *f_end;
const char *start;
const char *end;
const char *current;
return (EINVAL);
}
*p_error = 0;
if (description == NULL) {
return (ENOMEM);
}
/* Needed later to check for mandatory fields */
*session = sdp_new_session();
return (ENOMEM);
}
return (EINVAL);
}
SDP_MEMORY_ERROR)) {
/*
* RFC says parser SHOULD be tolerant to records ending
* with a single newline character too.
*/
f_end);
f_end);
} else {
current++;
}
}
return (ENOMEM);
}
/*
* Check for mandatory fields v, o, s, t fields. For connection field,
* RFC says; a connection field must be present in every media
* description or at the session-level
*/
description->d_mconn)))) {
}
return (0);
}