#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sdp.h>
#include "sdp_parse.h"
#include "commp_util.h"
static void
sdp_parse_version(int *version, const char *begin, const char *end,
uint_t *p_error)
{
if (*begin++ != COMMP_EQUALS || commp_atoi(begin, end, version) != 0)
*p_error |= SDP_VERSION_ERROR;
}
static void
sdp_parse_name(char **name, const char *begin, const char *end,
uint_t *p_error)
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_NAME_ERROR;
return;
}
if (*name != NULL)
return;
len = end - begin;
if (len < 1) {
*p_error |= SDP_NAME_ERROR;
} else {
COMMP_COPY_STR(*name, begin, len);
if (*name == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
static void
sdp_parse_info(char **info, const char *begin, const char *end,
uint_t *p_error)
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_INFO_ERROR;
return;
}
if (*info != NULL)
return;
len = end - begin;
if (len < 1) {
*p_error |= SDP_INFO_ERROR;
} else {
COMMP_COPY_STR(*info, begin, len);
if (*info == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
static void
sdp_parse_uri(char **uri, const char *begin, const char *end, uint_t *p_error)
{
int len;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_URI_ERROR;
return;
}
if (*uri != NULL)
return;
len = end - begin;
if (len < 1 || isspace(*begin) || isspace (*(end - 1))) {
*p_error |= SDP_URI_ERROR;
} else {
COMMP_COPY_STR(*uri, begin, len);
if (*uri == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
}
static void
sdp_parse_phone(sdp_list_t **phone, const char *begin, const char *end,
uint_t *p_error)
{
int len;
sdp_list_t *new_phone = NULL;
sdp_list_t *tmp = NULL;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_PHONE_ERROR;
return;
}
len = end - begin;
if (len < 1 || isspace(*begin) || isspace(*(end - 1))) {
*p_error |= SDP_PHONE_ERROR;
} else {
new_phone = calloc(1, sizeof (sdp_list_t));
if (new_phone == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
COMMP_COPY_STR(new_phone->value, begin, len);
if (new_phone->value == NULL) {
free(new_phone);
*p_error |= SDP_MEMORY_ERROR;
return;
}
if (*phone == NULL) {
*phone = new_phone;
} else {
tmp = *phone;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = new_phone;
}
}
}
static void
sdp_parse_email(sdp_list_t **email, const char *begin, const char *end,
uint_t *p_error)
{
int len;
sdp_list_t *new_email = NULL;
sdp_list_t *tmp = NULL;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_EMAIL_ERROR;
return;
}
len = end - begin;
if (len < 1 || isspace(*begin) || isspace(*(end - 1))) {
*p_error |= SDP_EMAIL_ERROR;
} else {
new_email = calloc(1, sizeof (sdp_list_t));
if (new_email == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
COMMP_COPY_STR(new_email->value, begin, len);
if (new_email->value == NULL) {
free(new_email);
*p_error |= SDP_MEMORY_ERROR;
return;
}
if (*email == NULL) {
*email = new_email;
} else {
tmp = *email;
while (tmp->next != NULL)
tmp = tmp->next;
tmp->next = new_email;
}
}
}
static void
sdp_parse_origin(sdp_origin_t **origin, const char *begin, const char *end,
uint_t *p_error)
{
const char *current = NULL;
sdp_origin_t *new_origin = NULL;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_ORIGIN_ERROR;
return;
}
if (*origin != NULL)
return;
new_origin = calloc(1, sizeof (sdp_origin_t));
if (new_origin == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_origin->o_username, begin, current - begin);
if (new_origin->o_username == NULL) {
sdp_free_origin(new_origin);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
if (commp_strtoull(begin, current, &new_origin->o_id) != 0)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
if (commp_strtoull(begin, current, &new_origin->o_version) != 0)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_origin->o_nettype, begin, current - begin);
if (new_origin->o_nettype == NULL) {
sdp_free_origin(new_origin);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_origin->o_addrtype, begin, current - begin);
if (new_origin->o_addrtype == NULL) {
sdp_free_origin(new_origin);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_TRUE) != 0)
goto err_ret;
COMMP_COPY_STR(new_origin->o_address, begin, current - begin);
if (new_origin->o_address == NULL) {
sdp_free_origin(new_origin);
*p_error |= SDP_MEMORY_ERROR;
return;
}
*origin = new_origin;
return;
err_ret:
*p_error |= SDP_ORIGIN_ERROR;
sdp_free_origin(new_origin);
}
static sdp_time_t *
sdp_parse_time(sdp_time_t **time, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_time_t *new_time;
sdp_time_t *tmp;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_TIME_ERROR;
return (NULL);
}
new_time = calloc(1, sizeof (sdp_time_t));
if (new_time == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
if (commp_strtoull(begin, current, &new_time->t_start) != 0)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_TRUE) != 0)
goto err_ret;
if (commp_strtoull(begin, current, &new_time->t_stop) != 0)
goto err_ret;
if (*time == NULL) {
*time = new_time;
} else {
tmp = *time;
while (tmp->t_next != NULL)
tmp = tmp->t_next;
tmp->t_next = new_time;
}
return (new_time);
err_ret:
*p_error |= SDP_TIME_ERROR;
sdp_free_time(new_time);
return (NULL);
}
static void
sdp_parse_connection(sdp_conn_t **conn, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
const char *t_begin;
const char *t_current;
sdp_conn_t *new_conn;
sdp_conn_t *tmp;
boolean_t is_IP4 = B_FALSE;
boolean_t is_IP6 = B_FALSE;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_CONNECTION_ERROR;
return;
}
new_conn = calloc(1, sizeof (sdp_conn_t));
if (new_conn == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_conn->c_nettype, begin, current - begin);
if (new_conn->c_nettype == NULL) {
sdp_free_connection(new_conn);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_conn->c_addrtype, begin, current - begin);
if (new_conn->c_addrtype == NULL) {
sdp_free_connection(new_conn);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
if ((strlen(COMMP_ADDRTYPE_IP4) == strlen(new_conn->c_addrtype)) &&
(strncasecmp(new_conn->c_addrtype, COMMP_ADDRTYPE_IP4,
strlen(COMMP_ADDRTYPE_IP4)) == 0)) {
is_IP4 = B_TRUE;
} else if ((strlen(COMMP_ADDRTYPE_IP6) == strlen(new_conn->
c_addrtype)) && (strncasecmp(new_conn->c_addrtype,
COMMP_ADDRTYPE_IP6, strlen(COMMP_ADDRTYPE_IP6)) == 0)) {
is_IP6 = B_TRUE;
}
begin = ++current;
if (!is_IP4 && !is_IP6) {
if (commp_find_token(&begin, ¤t, end, COMMP_SP,
B_TRUE) != 0) {
goto err_ret;
}
} else {
if (commp_find_token(&begin, ¤t, end, COMMP_SLASH,
B_FALSE) != 0) {
goto err_ret;
}
if (current != end) {
t_current = current;
t_begin = ++t_current;
if (commp_find_token(&t_begin, &t_current, end,
COMMP_SLASH, B_FALSE) != 0) {
goto err_ret;
}
if (t_current != end) {
if (is_IP6) {
goto err_ret;
} else {
if (commp_atoi((t_current + 1), end,
&new_conn->c_addrcount) != 0) {
goto err_ret;
}
}
}
if (is_IP6) {
if (commp_atoi((current + 1), t_current,
&new_conn->c_addrcount) != 0) {
goto err_ret;
}
} else {
if (commp_strtoub((current + 1), t_current,
&new_conn->c_ttl) != 0) {
goto err_ret;
}
if (new_conn->c_addrcount == 0)
new_conn->c_addrcount = 1;
}
}
}
COMMP_COPY_STR(new_conn->c_address, begin, current - begin);
if (new_conn->c_address == NULL) {
sdp_free_connection(new_conn);
*p_error |= SDP_MEMORY_ERROR;
return;
}
if (*conn == NULL) {
*conn = new_conn;
} else {
tmp = *conn;
while (tmp->c_next != NULL)
tmp = tmp->c_next;
tmp->c_next = new_conn;
}
return;
err_ret:
*p_error |= SDP_CONNECTION_ERROR;
sdp_free_connection(new_conn);
}
static void
sdp_parse_bandwidth(sdp_bandwidth_t **bw, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_bandwidth_t *new_bw = NULL;
sdp_bandwidth_t *tmp = NULL;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_BANDWIDTH_ERROR;
return;
}
new_bw = calloc(1, sizeof (sdp_bandwidth_t));
if (new_bw == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_COLON,
B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_bw->b_type, begin, current - begin);
if (new_bw->b_type == NULL) {
sdp_free_bandwidth(new_bw);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
if (current == end)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_TRUE) != 0)
goto err_ret;
if (commp_strtoull(begin, current, &new_bw->b_value) != 0)
goto err_ret;
if (*bw == NULL) {
*bw = new_bw;
} else {
tmp = *bw;
while (tmp->b_next != NULL)
tmp = tmp->b_next;
tmp->b_next = new_bw;
}
return;
err_ret:
*p_error |= SDP_BANDWIDTH_ERROR;
sdp_free_bandwidth(new_bw);
}
static void
sdp_parse_repeat(sdp_time_t *time, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_repeat_t *repeat;
sdp_repeat_t *new_repeat;
int ret;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_REPEAT_TIME_ERROR;
return;
}
if (time == NULL)
return;
while (time->t_next != NULL)
time = time->t_next;
new_repeat = calloc(1, sizeof (sdp_repeat_t));
if (new_repeat == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
repeat = time->t_repeat;
if (repeat == NULL) {
time->t_repeat = new_repeat;
} else {
while (repeat->r_next != NULL)
repeat = repeat->r_next;
repeat->r_next = new_repeat;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
if (commp_time_to_secs(begin, current, &new_repeat->r_interval) != 0)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
if (commp_time_to_secs(begin, current, &new_repeat->r_duration) != 0)
goto err_ret;
++current;
if (current >= end)
goto err_ret;
while (current < end) {
begin = current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP,
B_FALSE) != 0) {
goto err_ret;
}
if ((ret = add_value_to_list(&new_repeat->r_offset, begin,
current - begin, B_FALSE)) != 0) {
if (ret == ENOMEM) {
*p_error |= SDP_MEMORY_ERROR;
return;
} else {
goto err_ret;
}
}
++current;
}
if (isspace(*(end - 1)))
goto err_ret;
return;
err_ret:
*p_error |= SDP_REPEAT_TIME_ERROR;
if (repeat != NULL)
repeat->r_next = NULL;
else
time->t_repeat = NULL;
sdp_free_repeat(new_repeat);
}
static void
sdp_parse_zone(sdp_zone_t **zone, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_zone_t *new_zone = NULL;
sdp_zone_t *tmp = NULL;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_ZONE_ERROR;
return;
}
if (*zone != NULL)
return;
current = begin;
while (current < end) {
new_zone = calloc(1, sizeof (sdp_zone_t));
if (new_zone == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
if (*zone == NULL) {
*zone = new_zone;
tmp = *zone;
} else {
tmp->z_next = new_zone;
tmp = new_zone;
}
begin = current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP,
B_FALSE) != 0) {
goto err_ret;
}
if (commp_strtoull(begin, current, &new_zone->z_time) != 0)
goto err_ret;
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP,
B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_zone->z_offset, begin, current -
begin);
if (new_zone->z_offset == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
++current;
}
if (isspace(*(end - 1)))
goto err_ret;
return;
err_ret:
*p_error |= SDP_ZONE_ERROR;
sdp_free_zone(*zone);
*zone = NULL;
}
static void
sdp_parse_key(sdp_key_t **key, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_key_t *new_key;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_KEY_ERROR;
return;
}
if (*key != NULL)
return;
new_key = calloc(1, sizeof (sdp_key_t));
if (new_key == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_COLON,
B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_key->k_method, begin, current - begin);
if (new_key->k_method == NULL) {
sdp_free_key(new_key);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
if (*current == COMMP_COLON) {
++current;
if (current == end)
goto err_ret;
COMMP_COPY_STR(new_key->k_enckey, current, end - current);
if (new_key->k_enckey == NULL) {
sdp_free_key(new_key);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
*key = new_key;
return;
err_ret:
*p_error |= SDP_KEY_ERROR;
sdp_free_key(new_key);
}
static void
sdp_parse_attribute(sdp_attr_t **attr, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
sdp_attr_t *new_attr;
sdp_attr_t *tmp;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_ATTRIBUTE_ERROR;
return;
}
new_attr = calloc(1, sizeof (sdp_attr_t));
if (new_attr == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return;
}
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_COLON,
B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_attr->a_name, begin, current - begin);
if (new_attr->a_name == NULL) {
sdp_free_attribute(new_attr);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
if (*current == COMMP_COLON) {
++current;
if (current == end)
goto err_ret;
COMMP_COPY_STR(new_attr->a_value, current, end - current);
if (new_attr->a_value == NULL) {
sdp_free_attribute(new_attr);
*p_error |= SDP_MEMORY_ERROR;
return;
}
}
if (*attr == NULL) {
*attr = new_attr;
} else {
tmp = *attr;
while (tmp->a_next != NULL)
tmp = tmp->a_next;
tmp->a_next = new_attr;
}
return;
err_ret:
*p_error |= SDP_ATTRIBUTE_ERROR;
sdp_free_attribute(new_attr);
}
static sdp_media_t *
sdp_parse_media(sdp_session_t *session, const char *begin, const char *end,
uint_t *p_error)
{
const char *current;
const char *fake_end;
sdp_media_t *new_media;
sdp_media_t *tmp;
if (*begin++ != COMMP_EQUALS) {
*p_error |= SDP_MEDIA_ERROR;
return (NULL);
}
new_media = calloc(1, sizeof (sdp_media_t));
if (new_media == NULL) {
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
new_media->m_session = session;
current = begin;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_media->m_name, begin, current - begin);
if (new_media->m_name == NULL) {
sdp_free_media(new_media);
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0)
goto err_ret;
fake_end = current;
current = begin;
if (commp_find_token(&begin, ¤t, fake_end, COMMP_SLASH,
B_FALSE) != 0) {
goto err_ret;
}
if (commp_atoui(begin, current, &new_media->m_port) != 0)
goto err_ret;
if (*current == COMMP_SLASH) {
begin = ++current;
if (commp_find_token(&begin, ¤t, fake_end, COMMP_SP,
B_FALSE) != 0) {
goto err_ret;
}
if (commp_atoi(begin, current, &new_media->m_portcount) != 0)
goto err_ret;
} else {
new_media->m_portcount = 1;
}
begin = ++current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP, B_FALSE) != 0) {
goto err_ret;
} else {
COMMP_COPY_STR(new_media->m_proto, begin, current - begin);
if (new_media->m_proto == NULL) {
sdp_free_media(new_media);
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
}
++current;
if (current >= end)
goto err_ret;
while (current < end) {
begin = current;
if (commp_find_token(&begin, ¤t, end, COMMP_SP,
B_FALSE) != 0) {
goto err_ret;
}
if (add_value_to_list(&new_media->m_format, begin,
current - begin, B_TRUE) != 0) {
sdp_free_media(new_media);
*p_error |= SDP_MEMORY_ERROR;
return (NULL);
}
++current;
}
if (isspace(*(end - 1)))
goto err_ret;
tmp = session->s_media;
if (tmp == NULL) {
session->s_media = new_media;
} else {
while (tmp->m_next != NULL)
tmp = tmp->m_next;
tmp->m_next = new_media;
}
return (new_media);
err_ret:
*p_error |= SDP_MEDIA_ERROR;
sdp_free_media(new_media);
return (NULL);
}
static void
sdp_check_order(char prev, char *order, int *error)
{
*error = 0;
while (*order != '\0') {
if (*order++ == prev)
return;
}
*error = 1;
}
static void
sdp_handle_fields(sdp_description_t *description, sdp_session_t *_session,
const char *begin, const char *end)
{
boolean_t u_field = B_FALSE;
int error = 0;
char prev = description->d_prev;
char m_prev = description->d_mprev;
switch (*begin) {
case SDP_VERSION_FIELD:
sdp_check_order(prev, SDP_VERSION_ORDER, &error);
description->d_version = B_TRUE;
sdp_parse_version(&_session->s_version, begin + 1, end,
&description->d_perror);
break;
case SDP_ORIGIN_FIELD:
sdp_check_order(prev, SDP_ORIGIN_ORDER, &error);
description->d_origin = B_TRUE;
sdp_parse_origin(&_session->s_origin, begin + 1, end,
&description->d_perror);
break;
case SDP_NAME_FIELD:
sdp_check_order(prev, SDP_NAME_ORDER, &error);
description->d_name = B_TRUE;
sdp_parse_name(&_session->s_name, begin + 1, end,
&description->d_perror);
break;
case SDP_INFO_FIELD:
if (description->d_mparsed) {
sdp_check_order(m_prev, SDP_M_INFO_ORDER,
&error);
if (description->d_lmedia == NULL)
break;
sdp_parse_info(&(description->d_lmedia->
m_info), begin + 1, end, &description->
d_perror);
} else {
sdp_check_order(prev, SDP_INFO_ORDER, &error);
sdp_parse_info(&_session->s_info, begin + 1,
end, &description->d_perror);
}
break;
case SDP_URI_FIELD:
sdp_check_order(prev, SDP_URI_ORDER, &error);
sdp_parse_uri(&_session->s_uri, begin + 1, end,
&description->d_perror);
break;
case SDP_EMAIL_FIELD:
sdp_check_order(prev, SDP_EMAIL_ORDER, &error);
sdp_parse_email(&_session->s_email, begin + 1, end,
&description->d_perror);
break;
case SDP_PHONE_FIELD:
sdp_check_order(prev, SDP_PHONE_ORDER, &error);
sdp_parse_phone(&_session->s_phone, begin + 1, end,
&description->d_perror);
break;
case SDP_CONNECTION_FIELD:
if (description->d_mparsed) {
sdp_check_order(m_prev, SDP_M_CONN_ORDER,
&error);
--description->d_mccount;
if (description->d_lmedia == NULL)
break;
sdp_parse_connection(&(description->d_lmedia->
m_conn), begin + 1, end,
&description->d_perror);
} else {
sdp_check_order(prev, SDP_CONN_ORDER, &error);
description->d_conn = B_TRUE;
if (_session->s_conn != NULL)
break;
sdp_parse_connection(&_session->s_conn,
begin + 1, end, &description->d_perror);
}
break;
case SDP_BANDWIDTH_FIELD:
if (description->d_mparsed) {
sdp_check_order(m_prev, SDP_M_BW_ORDER, &error);
if (description->d_lmedia == NULL)
break;
sdp_parse_bandwidth(&(description->d_lmedia->
m_bw), begin + 1, end,
&description->d_perror);
} else {
sdp_check_order(prev, SDP_BW_ORDER, &error);
sdp_parse_bandwidth(&_session->s_bw,
begin + 1, end, &description->d_perror);
}
break;
case SDP_TIME_FIELD:
if (!description->d_tparsed || description->d_prev !=
SDP_REPEAT_FIELD) {
sdp_check_order(prev, SDP_TIME_ORDER, &error);
}
description->d_tparsed = B_TRUE;
description->d_ltime = sdp_parse_time(&_session->
s_time, begin + 1, end, &description->d_perror);
break;
case SDP_REPEAT_FIELD:
sdp_check_order(prev, SDP_REPEAT_ORDER, &error);
if (description->d_ltime == NULL)
break;
sdp_parse_repeat(description->d_ltime, begin + 1, end,
&description->d_perror);
break;
case SDP_ZONE_FIELD:
sdp_check_order(prev, SDP_ZONE_ORDER, &error);
sdp_parse_zone(&_session->s_zone, begin + 1, end,
&description->d_perror);
break;
case SDP_KEY_FIELD:
if (description->d_mparsed) {
sdp_check_order(m_prev, SDP_M_KEY_ORDER,
&error);
if (description->d_lmedia == NULL)
break;
sdp_parse_key(&(description->d_lmedia->m_key),
begin + 1, end, &description->d_perror);
} else {
sdp_check_order(prev, SDP_KEY_ORDER, &error);
sdp_parse_key(&_session->s_key, begin + 1, end,
&description->d_perror);
}
break;
case SDP_ATTRIBUTE_FIELD:
if (description->d_mparsed) {
sdp_check_order(m_prev, SDP_M_ATTR_ORDER,
&error);
if (description->d_lmedia == NULL)
break;
sdp_parse_attribute(&(description->d_lmedia->
m_attr), begin + 1, end,
&description->d_perror);
} else {
sdp_check_order(prev, SDP_ATTR_ORDER, &error);
sdp_parse_attribute(&_session->s_attr,
begin + 1, end, &description->d_perror);
}
break;
case SDP_MEDIA_FIELD:
if (!description->d_mparsed) {
sdp_check_order(prev, SDP_MEDIA_ORDER, &error);
description->d_mccount = 1;
} else {
if (description->d_mccount == 1)
description->d_mconn = B_FALSE;
description->d_mccount = 1;
}
description->d_mparsed = B_TRUE;
description->d_lmedia = sdp_parse_media(_session,
begin + 1, end, &description->d_perror);
break;
default:
u_field = B_TRUE;
break;
}
if (error)
description->d_perror |= SDP_FIELDS_ORDER_ERROR;
if (!u_field) {
if (!description->d_mparsed)
description->d_prev = *begin;
else
description->d_mprev = *begin;
}
}
int
sdp_parse(const char *sdp_info, int len, int flags, sdp_session_t **session,
uint_t *p_error)
{
const char *f_begin;
const char *f_end;
sdp_description_t *description;
const char *start;
const char *end;
const char *current;
if (sdp_info == NULL || len == 0 || p_error == NULL || flags != 0 ||
session == NULL) {
if (session != NULL)
*session = NULL;
return (EINVAL);
}
*session = NULL;
*p_error = 0;
description = calloc(1, sizeof (sdp_description_t));
if (description == NULL) {
return (ENOMEM);
}
description->d_prev = COMMP_SP;
description->d_mconn = B_TRUE;
*session = sdp_new_session();
if (*session == NULL) {
free(description);
return (ENOMEM);
}
start = sdp_info;
end = start + len;
if (commp_skip_white_space(&start, end) != 0) {
free(description);
free(*session);
*session = NULL;
return (EINVAL);
}
current = start;
f_begin = current;
while ((current < end) && !(description->d_perror &
SDP_MEMORY_ERROR)) {
if (strncmp(COMMP_CRLF, current, strlen(COMMP_CRLF)) == 0) {
f_end = current;
sdp_handle_fields(description, *session, f_begin,
f_end);
COMMP_SKIP_CRLF(current);
(void) commp_skip_white_space(¤t, end);
f_begin = current;
} else if (strncmp(COMMP_LF, current, strlen(COMMP_LF)) == 0) {
f_end = current;
sdp_handle_fields(description, *session, f_begin,
f_end);
COMMP_SKIP_LF(current);
(void) commp_skip_white_space(¤t, end);
f_begin = current;
} else {
current++;
}
}
if (description->d_perror & SDP_MEMORY_ERROR) {
free(description);
sdp_free_session(*session);
*session = NULL;
return (ENOMEM);
}
if (description->d_mccount == 1)
description->d_mconn = B_FALSE;
if (!(description->d_version && description->d_origin &&
description->d_name && description->d_tparsed &&
(description->d_conn || (description->d_mparsed &&
description->d_mconn)))) {
description->d_perror |= SDP_MISSING_FIELDS;
}
*p_error = description->d_perror;
free(description);
return (0);
}