diff options
Diffstat (limited to 'usr/src')
24 files changed, 3900 insertions, 0 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint index fb62aad36b..07be457327 100644 --- a/usr/src/Makefile.lint +++ b/usr/src/Makefile.lint @@ -312,6 +312,7 @@ COMMON_SUBDIRS = \ lib/libc_db \ lib/libcfgadm \ lib/libcmdutils \ + lib/libcommputil \ lib/libcontract \ lib/libcryptoutil \ lib/libctf \ diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile index bc98394c86..68613f9412 100644 --- a/usr/src/lib/Makefile +++ b/usr/src/lib/Makefile @@ -73,6 +73,7 @@ SUBDIRS += \ libsocket .WAIT \ libsctp \ libsip \ + libcommputil \ libresolv \ libresolv2 .WAIT \ libw .WAIT \ @@ -381,6 +382,7 @@ HDRSUBDIRS= \ librcm \ libscf \ libsip \ + libcommputil \ libsmbios \ librestart \ librpcsvc \ diff --git a/usr/src/lib/libcommputil/Makefile b/usr/src/lib/libcommputil/Makefile new file mode 100644 index 0000000000..af66849ca2 --- /dev/null +++ b/usr/src/lib/libcommputil/Makefile @@ -0,0 +1,53 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.lib + +HDRS = sdp.h +HDRDIR = common +SUBDIRS = $(MACH) +$(BUILD64)SUBDIRS += $(MACH64) + +all := TARGET= all +clean := TARGET= clean +clobber := TARGET= clobber +install := TARGET= install +lint := TARGET= lint + +.KEEP_STATE: + +all clean clobber install lint: $(SUBDIRS) + +install_h: $(ROOTHDRS) + +check: $(CHECKHDRS) + +$(SUBDIRS): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + +include ../Makefile.targ diff --git a/usr/src/lib/libcommputil/Makefile.com b/usr/src/lib/libcommputil/Makefile.com new file mode 100644 index 0000000000..9fd5f73e4a --- /dev/null +++ b/usr/src/lib/libcommputil/Makefile.com @@ -0,0 +1,48 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +LIBRARY = libcommputil.a +VERS = .1 +OBJECTS = commp_util.o sdp_parse_helper.o sdp.o sdp_parse.o + +include ../../Makefile.lib + +SRCDIR = ../common +LIBS = $(DYNLIB) $(LINTLIB) +$(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) +LDLIBS += -lc + +CFLAGS += -v -DOS='"solaris"' -D__OS_solaris -DNDEBUG + +CFLAGS64 += -v -DOS='"solaris"' -D__OS_solaris -DNDEBUG + +.KEEP_STATE: + +all: $(LIBS) + +lint: lintcheck + +include ../../Makefile.targ diff --git a/usr/src/lib/libcommputil/amd64/Makefile b/usr/src/lib/libcommputil/amd64/Makefile new file mode 100644 index 0000000000..b5538941d1 --- /dev/null +++ b/usr/src/lib/libcommputil/amd64/Makefile @@ -0,0 +1,30 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/lib/libcommputil/common/commp_util.c b/usr/src/lib/libcommputil/common/commp_util.c new file mode 100644 index 0000000000..8ed3464822 --- /dev/null +++ b/usr/src/lib/libcommputil/common/commp_util.c @@ -0,0 +1,220 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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" + +/* + * Helper functions to skip white spaces, find tokens, find separators and free + * memory. + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include "commp_util.h" + + +/* + * Skip to the next non-whitespace + */ +int +commp_skip_white_space(const char **begin, const char *end) +{ + while (*begin < end) { + if (!isspace(**begin)) + return (0); + (*begin)++; + } + return (1); +} + +/* + * Finds the token in the char buffer. *current will be pointing to the + * token when function returns. If the char buffer has leading token, + * it returns 1. + */ +int +commp_find_token(const char **begin, const char **current, const char *end, + char token, boolean_t last) +{ + *current = *begin; + while (*current < end) { + if (!last && (**current == token)) + break; + else if (isspace(**current)) + return (1); + (*current)++; + } + /* Checks for leading white space */ + if (*current == *begin) + return (1); + else + return (0); +} + +/* + * atoi function + */ +int +commp_atoi(const char *begin, const char *end, int *num) +{ + boolean_t num_found = B_FALSE; + + *num = 0; + while (begin < end) { + if (isdigit(*begin)) { + *num = (*num * 10) + (*begin - '0'); + num_found = B_TRUE; + begin++; + } else { + break; + } + } + if (!num_found || (begin != end)) + return (EINVAL); + return (0); +} + +/* + * Given a string converts it to unsigned long long int. + */ +int +commp_strtoull(const char *begin, const char *end, uint64_t *num) +{ + boolean_t num_found = B_FALSE; + + *num = 0; + while (begin < end) { + if (isdigit(*begin)) { + *num = (*num * 10) + (*begin - '0'); + num_found = B_TRUE; + begin++; + } else { + break; + } + } + if (!num_found || (begin != end)) + return (EINVAL); + return (0); +} + +/* + * Given a string converts it to unsigned byte + */ +int +commp_strtoub(const char *begin, const char *end, uint8_t *num) +{ + boolean_t num_found = B_FALSE; + + *num = 0; + while (begin < end) { + if (isdigit(*begin)) { + *num = (*num * 10) + (*begin - '0'); + num_found = B_TRUE; + begin++; + } else { + break; + } + } + if (!num_found || (begin != end)) + return (EINVAL); + return (0); +} + +/* + * Given a string converts it to unsigned int + */ +int +commp_atoui(const char *begin, const char *end, uint_t *num) +{ + boolean_t num_found = B_FALSE; + + *num = 0; + while (begin < end) { + if (isdigit(*begin)) { + *num = (*num * 10) + (*begin - '0'); + num_found = B_TRUE; + begin++; + } else { + break; + } + } + if (!num_found || (begin != end)) + return (EINVAL); + return (0); +} + +/* + * allocates memory and copies string to new memory + */ +int +commp_add_str(char **dest, const char *src, int len) +{ + if (len == 0) + return (EINVAL); + (*dest) = calloc(1, len + 1); + if (*dest == NULL) + return (ENOMEM); + (void) strncpy(*dest, src, len); + return (0); +} + +/* + * This function converts strings like "5d" to equivalent time in secs. + * For eg. 1h = 3600, 10d = 86400 + */ +int +commp_time_to_secs(const char *begin, const char *end, uint64_t *num) +{ + uint_t factor = 0; + + if (!isdigit(*(end - 1))) { + switch (*(end - 1)) { + case 'd': + factor = COMMP_SECS_IN_DAY; + break; + case 'h': + factor = COMMP_SECS_IN_HOUR; + break; + case 'm': + factor = COMMP_SECS_IN_MIN; + break; + case 's': + factor = 1; + break; + default: + return (EINVAL); + } + --end; + } + if (commp_strtoull(begin, end, num) != 0) + return (EINVAL); + if (factor != 0) + (*num) = (*num) * factor; + return (0); +} diff --git a/usr/src/lib/libcommputil/common/commp_util.h b/usr/src/lib/libcommputil/common/commp_util.h new file mode 100644 index 0000000000..e968dc88cf --- /dev/null +++ b/usr/src/lib/libcommputil/common/commp_util.h @@ -0,0 +1,76 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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. + */ + +#ifndef _COMMP_UTIL_H +#define _COMMP_UTIL_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define COMMP_CRLF "\r\n" +#define COMMP_LF "\n" +#define COMMP_SKIP_CRLF(msg_ptr) ((msg_ptr) = (msg_ptr) + 2) +#define COMMP_SKIP_LF(msg_ptr) ((msg_ptr) = (msg_ptr) + 1) + +#define COMMP_SECS_IN_DAY 86400 +#define COMMP_SECS_IN_HOUR 3600 +#define COMMP_SECS_IN_MIN 60 + +#define COMMP_SP ' ' +#define COMMP_CR '\r' +#define COMMP_COLON ':' +#define COMMP_SLASH '/' +#define COMMP_EQUALS '=' +#define COMMP_ADDRTYPE_IP4 "IP4" +#define COMMP_ADDRTYPE_IP6 "IP6" + +#define COMMP_COPY_STR(dst, src, len) { \ + (dst) = calloc(1, (len) + 1); \ + if ((dst) != NULL) { \ + (void) strncpy((dst), (src), (len)); \ + } \ +} + +extern int commp_skip_white_space(const char **, const char *); +extern int commp_find_token(const char **, const char **, const char *, + char, boolean_t); +extern int commp_atoi(const char *, const char *, int *); +extern int commp_strtoull(const char *, const char *, uint64_t *); +extern int commp_strtoub(const char *, const char *, uint8_t *); +extern int commp_atoui(const char *, const char *, uint_t *); +extern int commp_time_to_secs(const char *, const char *, uint64_t *); +extern int commp_add_str(char **, const char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _COMMP_UTIL_H */ diff --git a/usr/src/lib/libcommputil/common/llib-lcommputil b/usr/src/lib/libcommputil/common/llib-lcommputil new file mode 100644 index 0000000000..834e4c80ac --- /dev/null +++ b/usr/src/lib/libcommputil/common/llib-lcommputil @@ -0,0 +1,31 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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" + +/* LINTLIBRARY */ +/* PROTOLIB1 */ +#include <sdp.h> diff --git a/usr/src/lib/libcommputil/common/mapfile-vers b/usr/src/lib/libcommputil/common/mapfile-vers new file mode 100644 index 0000000000..97508f14bc --- /dev/null +++ b/usr/src/lib/libcommputil/common/mapfile-vers @@ -0,0 +1,58 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +SUNW_1.1 { + global: + sdp_parse; + sdp_find_media; + sdp_find_attribute; + sdp_find_media_rtpmap; + sdp_clone_session; + sdp_new_session; + sdp_add_origin; + sdp_add_name; + sdp_add_information; + sdp_add_uri; + sdp_add_email; + sdp_add_phone; + sdp_add_connection; + sdp_add_bandwidth; + sdp_add_repeat; + sdp_add_time; + sdp_add_zone; + sdp_add_key; + sdp_add_attribute; + sdp_add_media; + sdp_session_to_str; + sdp_delete_all_field; + sdp_delete_all_media_field; + sdp_delete_media; + sdp_delete_attribute; + sdp_free_session; + local: + *; +}; diff --git a/usr/src/lib/libcommputil/common/sdp.c b/usr/src/lib/libcommputil/common/sdp.c new file mode 100644 index 0000000000..f322029479 --- /dev/null +++ b/usr/src/lib/libcommputil/common/sdp.c @@ -0,0 +1,1299 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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" + +/* + * Contains implementation of various interfaces exported by library + */ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sdp.h> + +#include "sdp_parse.h" +#include "commp_util.h" + +#define FIELD_EQUALS_CRLF_LEN 4 /* first two characters and CRLF */ + +#define SDP_ATTR_TO_STR(m_attr) { \ + while ((m_attr) != NULL) { \ + if ((m_attr)->a_value != NULL) { \ + wrote = snprintf(buf, len, "a=%s%c%s%s", \ + (m_attr)->a_name, COMMP_COLON, (m_attr)-> \ + a_value, COMMP_CRLF); \ + } else { \ + wrote = snprintf(buf, len, "a=%s%s", (m_attr)-> \ + a_name, COMMP_CRLF); \ + } \ + len = len - wrote; \ + buf = buf + wrote; \ + (m_attr) = (m_attr)->a_next; \ + } \ +} + +#define SDP_KEY_TO_STR(m_key) { \ + if ((m_key) != NULL) { \ + if ((m_key)->k_enckey != NULL) { \ + wrote = snprintf(buf, len, "k=%s%c%s%s", \ + (m_key)->k_method, COMMP_COLON, (m_key)-> \ + k_enckey, COMMP_CRLF); \ + } else { \ + wrote = snprintf(buf, len, "k=%s%s", (m_key)-> \ + k_method, COMMP_CRLF); \ + } \ + len = len - wrote; \ + buf = buf + wrote; \ + } \ +} + +#define SDP_BANDWIDTH_TO_STR(m_bw) { \ + while ((m_bw) != NULL) { \ + wrote = snprintf(buf, len, "b=%s%c%llu%s", (m_bw)-> \ + b_type, COMMP_COLON, (m_bw)->b_value, COMMP_CRLF); \ + len = len - wrote; \ + buf = buf + wrote; \ + (m_bw) = (m_bw)->b_next; \ + } \ +} + +#define SDP_INFORMATION_TO_STR(m_info) { \ + if ((m_info) != NULL) { \ + wrote = snprintf(buf, len, "i=%s%s", (m_info), COMMP_CRLF); \ + len = len - wrote; \ + buf = buf + wrote; \ + } \ +} + +#define SDP_CONNECTION_TO_STR(m_conn) { \ + while ((m_conn) != NULL) { \ + if (strcasecmp((m_conn)->c_addrtype, \ + COMMP_ADDRTYPE_IP4) == 0) { \ + if ((m_conn)->c_addrcount > 1) { \ + wrote = snprintf(buf, len, "c=%s %s %s/%d/%d" \ + "%s", (m_conn)->c_nettype, (m_conn)-> \ + c_addrtype, (m_conn)->c_address, (m_conn)->\ + c_ttl, (m_conn)->c_addrcount, COMMP_CRLF); \ + } else if ((m_conn)->c_addrcount == 1) { \ + wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \ + (m_conn)->c_nettype, (m_conn)->c_addrtype, \ + (m_conn)->c_address, (m_conn)->c_ttl, \ + COMMP_CRLF); \ + } else { \ + wrote = snprintf(buf, len, "c=%s %s %s%s", \ + (m_conn)->c_nettype, (m_conn)->c_addrtype, \ + (m_conn)->c_address, COMMP_CRLF); \ + } \ + } else if (strcasecmp((m_conn)->c_addrtype, \ + COMMP_ADDRTYPE_IP6) == 0) { \ + if ((m_conn)->c_addrcount <= 1) { \ + wrote = snprintf(buf, len, "c=%s %s %s%s", \ + (m_conn)->c_nettype, (m_conn)->c_addrtype, \ + (m_conn)->c_address, COMMP_CRLF); \ + } else { \ + wrote = snprintf(buf, len, "c=%s %s %s/%d%s", \ + (m_conn)->c_nettype, (m_conn)->c_addrtype, \ + (m_conn)->c_address, (m_conn)->c_addrcount,\ + COMMP_CRLF); \ + } \ + } else { \ + wrote = snprintf(buf, len, "c=%s %s %s%s", (m_conn)-> \ + c_nettype, (m_conn)->c_addrtype, (m_conn)-> \ + c_address, COMMP_CRLF); \ + } \ + len = len - wrote; \ + buf = buf + wrote; \ + (m_conn) = (m_conn)->c_next; \ + } \ +} + +#define SDP_ADD_KEY(d_key, s_key) { \ + if ((s_key) != NULL) { \ + if (sdp_add_key(&(d_key), (s_key)->k_method, \ + (s_key)->k_enckey) != 0) { \ + sdp_free_session(new_sess); \ + return (NULL); \ + } \ + } \ +} + +#define SDP_ADD_ATTRIBUTE(d_attr, s_attr) { \ + while ((s_attr) != NULL) { \ + if (sdp_add_attribute(&(d_attr), (s_attr)->a_name, \ + (s_attr)->a_value) != 0) { \ + sdp_free_session(new_sess); \ + return (NULL); \ + } \ + (s_attr) = (s_attr)->a_next; \ + } \ +} + +#define SDP_ADD_BANDWIDTH(d_bw, s_bw) { \ + while ((s_bw) != NULL) { \ + if (sdp_add_bandwidth(&(d_bw), (s_bw)->b_type, \ + (s_bw)->b_value) != 0) { \ + sdp_free_session(new_sess); \ + return (NULL); \ + } \ + (s_bw) = (s_bw)->b_next; \ + } \ +} + +#define SDP_ADD_CONNECTION(d_conn, s_conn) { \ + while ((s_conn) != NULL) { \ + if (sdp_add_connection(&(d_conn), (s_conn)->c_nettype, \ + (s_conn)->c_addrtype, (s_conn)->c_address, \ + (s_conn)->c_ttl, (s_conn)->c_addrcount) != 0) { \ + sdp_free_session(new_sess); \ + return (NULL); \ + } \ + (s_conn) = (s_conn)->c_next; \ + } \ +} + +#define SDP_LEN_CONNECTION(m_conn) { \ + while ((m_conn) != NULL) { \ + len += FIELD_EQUALS_CRLF_LEN; \ + len += strlen((m_conn)->c_nettype); \ + len += strlen((m_conn)->c_addrtype) + 1; \ + len += strlen((m_conn)->c_address) + 1; \ + len += snprintf(buf, 1, "%u", (m_conn)->c_ttl) + 1; \ + len += snprintf(buf, 1, "%d", (m_conn)->c_addrcount) + 1; \ + (m_conn) = (m_conn)->c_next; \ + } \ +} + +#define SDP_LEN_BANDWIDTH(m_bw) { \ + while ((m_bw) != NULL) { \ + len += FIELD_EQUALS_CRLF_LEN; \ + len += strlen((m_bw)->b_type); \ + len += snprintf(buf, 1, "%llu", (m_bw)->b_value) + 1; \ + (m_bw) = (m_bw)->b_next; \ + } \ +} + +#define SDP_LEN_KEY(m_key) { \ + if ((m_key) != NULL) { \ + len += FIELD_EQUALS_CRLF_LEN; \ + len += strlen((m_key)->k_method); \ + if ((m_key)->k_enckey != NULL) \ + len += strlen((m_key)->k_enckey) + 1; \ + } \ +} + +#define SDP_LEN_ATTRIBUTE(m_attr) { \ + while ((m_attr) != NULL) { \ + len += FIELD_EQUALS_CRLF_LEN; \ + len += strlen((m_attr)->a_name); \ + if ((m_attr)->a_value != NULL) \ + len += strlen((m_attr)->a_value) + 1; \ + (m_attr) = (m_attr)->a_next; \ + } \ +} + +/* + * Given a media list and media name ("audio", "video", et al), it searches + * the list for that media. Returns NULL if media not present. + */ +sdp_media_t * +sdp_find_media(sdp_media_t *media, const char *name) +{ + if (media == NULL || name == NULL || (strlen(name) == 0)) { + return (NULL); + } + while (media != NULL) { + if (media->m_name != NULL) { + if (strcasecmp(name, media->m_name) == 0) + return (media); + } + media = media->m_next; + } + return (media); +} + +/* + * Given a attribute list and name of the attribute ("rtpmap", "fmtp", et al), + * this API searches the list for that attribute. Returns NULL if not found. + */ +sdp_attr_t * +sdp_find_attribute(sdp_attr_t *attr, const char *name) +{ + if (attr == NULL || name == NULL || (strlen(name) == 0)) { + return (NULL); + } + while (attr != NULL) { + if (attr->a_name != NULL) { + if (strcasecmp(attr->a_name, name) == 0) + return (attr); + } + attr = attr->a_next; + } + return (attr); +} + +/* + * Given a media list and a format number, this API will return the rtpmap + * attribute matching the format number. + */ +sdp_attr_t * +sdp_find_media_rtpmap(sdp_media_t *media, const char *format) +{ + sdp_attr_t *attr = NULL; + char *tmp = NULL; + + if (media == NULL || format == NULL || (strlen(format) == 0)) { + return (NULL); + } + attr = media->m_attr; + while (attr != NULL) { + if (attr->a_name != NULL && (strcasecmp(attr->a_name, + SDP_RTPMAP) == 0)) { + if (attr->a_value != NULL) { + tmp = attr->a_value; + while (isspace(*tmp)) + ++tmp; + if (strncasecmp(tmp, format, + strlen(format)) == 0) { + return (attr); + } + } + } + attr = attr->a_next; + } + return (attr); +} + +/* + * Adds origin field to the session. + * o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address> + */ +int +sdp_add_origin(sdp_session_t *session, const char *name, uint64_t id, + uint64_t ver, const char *nettype, const char *addrtype, + const char *address) +{ + sdp_origin_t *origin; + int ret = 0; + + if (session == NULL || name == NULL || nettype == NULL || + addrtype == NULL || address == NULL) { + return (EINVAL); + } + if (session->s_origin != NULL) + return (EPROTO); + origin = calloc(1, sizeof (sdp_origin_t)); + if (origin == NULL) + return (ENOMEM); + origin->o_id = id; + origin->o_version = ver; + if ((ret = commp_add_str(&origin->o_username, name, strlen(name))) != 0) + goto err_ret; + if ((ret = commp_add_str(&origin->o_nettype, nettype, + strlen(nettype))) != 0) { + goto err_ret; + } + if ((ret = commp_add_str(&origin->o_addrtype, addrtype, + strlen(addrtype))) != 0) { + goto err_ret; + } + if ((ret = commp_add_str(&origin->o_address, address, + strlen(address))) != 0) { + goto err_ret; + } + session->s_origin = origin; + return (ret); +err_ret: + sdp_free_origin(origin); + return (ret); +} + +/* + * Adds session name field to the session. + * s=<session name> + */ +int +sdp_add_name(sdp_session_t *session, const char *name) +{ + if (session == NULL || name == NULL) + return (EINVAL); + if (session->s_name != NULL) + return (EPROTO); + return (commp_add_str(&session->s_name, name, strlen(name))); +} + +/* + * Adds session information field to the session or media section of SDP. + * i=<session description> + */ +int +sdp_add_information(char **information, const char *value) +{ + if (information == NULL || value == NULL) + return (EINVAL); + if (*information != NULL) + return (EPROTO); + return (commp_add_str(information, value, strlen(value))); +} + +/* + * Adds uri field to the session. + * u=<uri> + */ +int +sdp_add_uri(sdp_session_t *session, const char *uri) +{ + if (session == NULL || uri == NULL) + return (EINVAL); + if (session->s_uri != NULL) + return (EPROTO); + return (commp_add_str(&session->s_uri, uri, strlen(uri))); +} + +/* + * Adds email address field to the session. + * e=<email-address> + */ +int +sdp_add_email(sdp_session_t *session, const char *email) +{ + if (session == NULL || email == NULL || (strlen(email) == 0)) + return (EINVAL); + return (add_value_to_list(&session->s_email, email, strlen(email), + B_TRUE)); +} + +/* + * Adds phone number field to the session. + * p=<phone-number> + */ +int +sdp_add_phone(sdp_session_t *session, const char *phone) +{ + if (session == NULL || phone == NULL || (strlen(phone) == 0)) + return (EINVAL); + return (add_value_to_list(&session->s_phone, phone, strlen(phone), + B_TRUE)); +} + +/* + * Adds connection field to the session or media section of SDP + * c=<nettype> <addrtype> <connection-address>[/ttl]/<number of addresses> + */ +int +sdp_add_connection(sdp_conn_t **conn, const char *nettype, const char *addrtype, + const char *address, uint8_t ttl, int addrcount) +{ + sdp_conn_t *tmp; + sdp_conn_t *new_conn; + int ret = 0; + + if (conn == NULL || nettype == NULL || addrtype == NULL || + address == NULL) { + return (EINVAL); + } + new_conn = calloc(1, sizeof (sdp_conn_t)); + if (new_conn == NULL) + return (ENOMEM); + new_conn->c_ttl = ttl; + new_conn->c_addrcount = addrcount; + if ((ret = commp_add_str(&new_conn->c_nettype, nettype, + strlen(nettype))) != 0) { + goto err_ret; + } + if ((ret = commp_add_str(&new_conn->c_addrtype, addrtype, + strlen(addrtype))) != 0) { + goto err_ret; + } + if ((ret = commp_add_str(&new_conn->c_address, address, + strlen(address))) != 0) { + goto err_ret; + } + if (*conn == NULL) { + *conn = new_conn; + } else { + tmp = *conn; + while (tmp->c_next != NULL) + tmp = tmp->c_next; + tmp->c_next = new_conn; + } + return (ret); +err_ret: + sdp_free_connection(new_conn); + return (ret); +} + +/* + * Adds bandwidth field to the session or media section of SDP. + * b=<bwtype>:<bandwidth> + */ +int +sdp_add_bandwidth(sdp_bandwidth_t **bw, const char *type, uint64_t value) +{ + sdp_bandwidth_t *new_bw; + sdp_bandwidth_t *tmp; + int ret = 0; + + if (bw == NULL || type == NULL) + return (EINVAL); + new_bw = calloc(1, sizeof (sdp_bandwidth_t)); + if (new_bw == NULL) + return (ENOMEM); + new_bw->b_value = value; + if ((ret = commp_add_str(&new_bw->b_type, type, strlen(type))) != 0) { + free(new_bw); + return (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 (ret); +} + +/* + * Adds time field to the session + * t=<start-time> <stop-time> + */ +int +sdp_add_time(sdp_session_t *session, uint64_t starttime, uint64_t stoptime, + sdp_time_t **time) +{ + sdp_time_t *new_time; + sdp_time_t *tmp; + + if (time != NULL) + *time = NULL; + if (session == NULL) { + return (EINVAL); + } + new_time = calloc(1, sizeof (sdp_time_t)); + if (new_time == NULL) { + return (ENOMEM); + } + new_time->t_start = starttime; + new_time->t_stop = stoptime; + tmp = session->s_time; + if (tmp == NULL) + session->s_time = new_time; + else { + while (tmp->t_next != NULL) + tmp = tmp->t_next; + tmp->t_next = new_time; + } + if (time != NULL) + *time = new_time; + return (0); +} + +/* + * Adds repeat field to the time structure of session + * r=<repeat interval> <active duration> <offsets from start-time> + */ +int +sdp_add_repeat(sdp_time_t *time, uint64_t interval, uint64_t duration, + const char *offset) +{ + sdp_repeat_t *tmp; + sdp_repeat_t *new_repeat; + int ret = 0; + + if (time == NULL || offset == NULL) + return (EINVAL); + new_repeat = calloc(1, sizeof (sdp_repeat_t)); + if (new_repeat == NULL) + return (ENOMEM); + new_repeat->r_interval = interval; + new_repeat->r_duration = duration; + if ((ret = sdp_str_to_list(&new_repeat->r_offset, offset, + strlen(offset), B_FALSE)) != 0) { + goto err_ret; + } + tmp = time->t_repeat; + if (tmp == NULL) { + time->t_repeat = new_repeat; + } else { + while (tmp->r_next != NULL) + tmp = tmp->r_next; + tmp->r_next = new_repeat; + } + return (ret); +err_ret: + sdp_free_repeat(new_repeat); + return (ret); +} + +/* + * Adds time zone field to the session + * z=<adjustment time> <offset> <adjustment time> <offset> .... + */ +int +sdp_add_zone(sdp_session_t *session, uint64_t time, const char *offset) +{ + sdp_zone_t *new_zone; + sdp_zone_t *tmp; + int ret = 0; + + if (session == NULL || offset == NULL) + return (EINVAL); + new_zone = calloc(1, sizeof (sdp_zone_t)); + if (new_zone == NULL) + return (ENOMEM); + new_zone->z_time = time; + if ((ret = commp_add_str(&new_zone->z_offset, offset, + strlen(offset))) != 0) { + free(new_zone); + return (ret); + } + tmp = session->s_zone; + if (tmp == NULL) { + session->s_zone = new_zone; + } else { + while (tmp->z_next != NULL) { + tmp = tmp->z_next; + } + tmp->z_next = new_zone; + } + return (ret); +} + +/* + * Adds key field to session or media section of SDP. + * k=<method> + * k=<method>:<encryption key> + */ +int +sdp_add_key(sdp_key_t **key, const char *method, const char *enckey) +{ + int ret = 0; + + if (key == NULL || method == NULL) + return (EINVAL); + if (*key != NULL) + return (EPROTO); + *key = calloc(1, sizeof (sdp_key_t)); + if (*key == NULL) + return (ENOMEM); + if ((ret = commp_add_str(&((*key)->k_method), method, + strlen(method))) != 0) { + goto err_ret; + } + if (enckey != NULL) { + if ((ret = commp_add_str(&((*key)->k_enckey), enckey, + strlen(enckey))) != 0) { + goto err_ret; + } + } + return (ret); +err_ret: + sdp_free_key(*key); + *key = NULL; + return (ret); +} + +/* + * Adds attribute field to session or media section of SDP. + * a=<attribute> + * a=<attribute>:<value> + */ +int +sdp_add_attribute(sdp_attr_t **attr, const char *name, const char *value) +{ + sdp_attr_t *tmp; + sdp_attr_t *new_attr; + int ret = 0; + + if (attr == NULL || name == NULL) + return (EINVAL); + new_attr = calloc(1, sizeof (sdp_attr_t)); + if (new_attr == NULL) + return (ENOMEM); + if ((ret = commp_add_str(&new_attr->a_name, name, strlen(name))) != 0) + goto err_ret; + if (value != NULL) { + if ((ret = commp_add_str(&new_attr->a_value, value, + strlen(value))) != 0) { + goto err_ret; + } + } + tmp = *attr; + if (tmp == NULL) { + *attr = new_attr; + } else { + while (tmp->a_next != NULL) + tmp = tmp->a_next; + tmp->a_next = new_attr; + } + return (ret); +err_ret: + sdp_free_attribute(new_attr); + return (ret); +} + +/* + * Adds media field to the session. + * m=<media> <port>[/portcount] <proto> <fmt> ... + */ +int +sdp_add_media(sdp_session_t *session, const char *name, uint_t port, + int portcount, const char *protocol, const char *fmt, sdp_media_t **media) +{ + sdp_media_t *tmp; + sdp_media_t *new_media; + int ret = 0; + + if (media != NULL) + *media = NULL; + if (session == NULL || name == NULL || protocol == NULL || + portcount <= 0 || fmt == NULL) { + return (EINVAL); + } + new_media = calloc(1, sizeof (sdp_media_t)); + if (new_media == NULL) { + return (ENOMEM); + } + new_media->m_session = session; + new_media->m_port = port; + new_media->m_portcount = portcount; + if ((ret = commp_add_str(&new_media->m_name, name, strlen(name))) != 0) + goto err_ret; + if ((ret = commp_add_str(&new_media->m_proto, protocol, + strlen(protocol))) != 0) { + goto err_ret; + } + if ((ret = sdp_str_to_list(&new_media->m_format, fmt, + strlen(fmt), B_TRUE)) != 0) { + 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; + } + if (media != NULL) + *media = new_media; + return (0); +err_ret: + sdp_free_media(new_media); + return (ret); +} + +/* + * This internal API is required by sdp_session_to_str(). It determines the + * length of buffer that is required to hold the session. Since the RFC does + * not limit the size of various sub-fields in the field. We need to scan + * through the structure to determine the length. + */ +int +sdp_get_length(const sdp_session_t *session) +{ + int len = 0; + char buf[1]; + sdp_list_t *list; + sdp_conn_t *conn; + sdp_bandwidth_t *bw; + sdp_zone_t *zone; + sdp_time_t *time; + sdp_repeat_t *repeat; + sdp_attr_t *attr; + sdp_media_t *media; + + len += FIELD_EQUALS_CRLF_LEN; + len += snprintf(buf, 1, "%d", session->s_version); + if (session->s_origin != NULL) { + len += FIELD_EQUALS_CRLF_LEN; + len += strlen(session->s_origin->o_username); + len += snprintf(buf, 1, "%llu", session->s_origin->o_id) + 1; + len += snprintf(buf, 1, "%llu", session->s_origin->o_version) + + 1; + len += strlen(session->s_origin->o_nettype) + 1; + len += strlen(session->s_origin->o_addrtype) + 1; + len += strlen(session->s_origin->o_address) + 1; + } + if (session->s_name != NULL) + len += strlen(session->s_name) + FIELD_EQUALS_CRLF_LEN; + if (session->s_info != NULL) + len += strlen(session->s_info) + FIELD_EQUALS_CRLF_LEN; + if (session->s_uri != NULL) + len += strlen(session->s_uri) + FIELD_EQUALS_CRLF_LEN; + list = session->s_email; + while (list != NULL) { + len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN; + list = list->next; + } + list = session->s_phone; + while (list != NULL) { + len += strlen((char *)list->value) + FIELD_EQUALS_CRLF_LEN; + list = list->next; + } + conn = session->s_conn; + SDP_LEN_CONNECTION(conn); + bw = session->s_bw; + SDP_LEN_BANDWIDTH(bw); + time = session->s_time; + while (time != NULL) { + len += FIELD_EQUALS_CRLF_LEN; + len += snprintf(buf, 1, "%llu", time->t_start); + len += snprintf(buf, 1, "%llu", time->t_stop) + 1; + repeat = time->t_repeat; + while (repeat != NULL) { + len += FIELD_EQUALS_CRLF_LEN; + len += snprintf(buf, 1, "%llu", repeat->r_interval); + len += snprintf(buf, 1, "%llu", repeat->r_duration) + 1; + list = repeat->r_offset; + while (list != NULL) { + len += snprintf(buf, 1, "%llu", + *(uint64_t *)list->value) + 1; + list = list->next; + } + repeat = repeat->r_next; + } + time = time->t_next; + } + if (session->s_zone != NULL) + len += FIELD_EQUALS_CRLF_LEN; + zone = session->s_zone; + while (zone != NULL) { + len += snprintf(buf, 1, "%llu", zone->z_time) + 1; + len += strlen(zone->z_offset) + 1; + zone = zone->z_next; + } + SDP_LEN_KEY(session->s_key); + attr = session->s_attr; + SDP_LEN_ATTRIBUTE(attr); + media = session->s_media; + while (media != NULL) { + len += FIELD_EQUALS_CRLF_LEN; + len += strlen(media->m_name); + len += snprintf(buf, 1, "%u", media->m_port) + 1; + len += snprintf(buf, 1, "%d", media->m_portcount) + 1; + len += strlen(media->m_proto) + 1; + list = media->m_format; + while (list != NULL) { + len += strlen((char *)list->value) + 1; + list = list->next; + } + if (media->m_info != NULL) + len += strlen(media->m_info) + FIELD_EQUALS_CRLF_LEN; + conn = media->m_conn; + SDP_LEN_CONNECTION(conn); + bw = media->m_bw; + SDP_LEN_BANDWIDTH(bw); + SDP_LEN_KEY(media->m_key); + attr = media->m_attr; + SDP_LEN_ATTRIBUTE(attr); + media = media->m_next; + } + return (len); +} + +/* + * Given a session structure it clones (deep copy) and returns the cloned copy + */ +sdp_session_t * +sdp_clone_session(const sdp_session_t *session) +{ + sdp_session_t *new_sess; + sdp_origin_t *origin; + sdp_list_t *list; + sdp_time_t *time; + sdp_time_t *new_time; + sdp_repeat_t *repeat; + sdp_media_t *media; + sdp_media_t *new_media; + sdp_conn_t *conn; + sdp_bandwidth_t *bw; + sdp_attr_t *attr; + sdp_zone_t *zone; + char *offset = NULL; + char *format = NULL; + + if (session == NULL) + return (NULL); + new_sess = calloc(1, sizeof (sdp_session_t)); + if (new_sess == NULL) + return (NULL); + new_sess->sdp_session_version = session->sdp_session_version; + new_sess->s_version = session->s_version; + origin = session->s_origin; + if (origin != NULL && (sdp_add_origin(new_sess, origin->o_username, + origin->o_id, origin->o_version, origin->o_nettype, origin-> + o_addrtype, origin->o_address) != 0)) { + goto err_ret; + } + if (session->s_name != NULL && sdp_add_name(new_sess, session-> + s_name) != 0) { + goto err_ret; + } + if (session->s_info != NULL && sdp_add_information(&new_sess-> + s_info, session->s_info) != 0) { + goto err_ret; + } + if (session->s_uri != NULL && sdp_add_uri(new_sess, session-> + s_uri) != 0) { + goto err_ret; + } + list = session->s_email; + while (list != NULL) { + if (sdp_add_email(new_sess, (char *)list->value) != 0) + goto err_ret; + list = list->next; + } + list = session->s_phone; + while (list != NULL) { + if (sdp_add_phone(new_sess, (char *)list->value) != 0) + goto err_ret; + list = list->next; + } + conn = session->s_conn; + SDP_ADD_CONNECTION(new_sess->s_conn, conn); + bw = session->s_bw; + SDP_ADD_BANDWIDTH(new_sess->s_bw, bw); + time = session->s_time; + while (time != NULL) { + if (sdp_add_time(new_sess, time->t_start, time->t_stop, + &new_time) != 0) { + goto err_ret; + } + repeat = time->t_repeat; + while (repeat != NULL) { + if (sdp_list_to_str(repeat->r_offset, &offset, + B_FALSE) != 0) { + goto err_ret; + } + if (sdp_add_repeat(new_time, repeat->r_interval, + repeat->r_duration, offset) != 0) { + free(offset); + goto err_ret; + } + free(offset); + repeat = repeat->r_next; + } + time = time->t_next; + } + zone = session->s_zone; + while (zone != NULL) { + if (sdp_add_zone(new_sess, zone->z_time, zone->z_offset) != 0) + goto err_ret; + zone = zone->z_next; + } + SDP_ADD_KEY(new_sess->s_key, session->s_key); + attr = session->s_attr; + SDP_ADD_ATTRIBUTE(new_sess->s_attr, attr); + media = session->s_media; + while (media != NULL) { + if (sdp_list_to_str(media->m_format, &format, B_TRUE) != 0) + goto err_ret; + if (sdp_add_media(new_sess, media->m_name, + media->m_port, media->m_portcount, media->m_proto, + format, &new_media) != 0) { + free(format); + goto err_ret; + } + free(format); + if (media->m_info != NULL) { + if (sdp_add_information(&new_media->m_info, + media->m_info) != 0) { + goto err_ret; + } + } + conn = media->m_conn; + SDP_ADD_CONNECTION(new_media->m_conn, conn); + bw = media->m_bw; + SDP_ADD_BANDWIDTH(new_media->m_bw, bw); + SDP_ADD_KEY(new_media->m_key, media->m_key); + attr = media->m_attr; + SDP_ADD_ATTRIBUTE(new_media->m_attr, attr); + new_media->m_session = new_sess; + media = media->m_next; + } + return (new_sess); +err_ret: + sdp_free_session(new_sess); + return (NULL); +} + +/* + * should i check if individual members are NULL, if not snprintf + * will core dump. + */ +/* + * Given a session structure, this API converts it into character + * buffer, which will be used as a payload later on. + */ +char * +sdp_session_to_str(const sdp_session_t *session, int *error) +{ + char *ret = NULL; + char *buf = NULL; + int len = 0; + int s_len = 0; + int wrote = 0; + sdp_origin_t *origin; + sdp_list_t *list; + sdp_conn_t *conn; + sdp_attr_t *attr; + sdp_bandwidth_t *bw; + sdp_time_t *time; + sdp_repeat_t *repeat; + sdp_zone_t *zone; + sdp_media_t *media; + + if (error != NULL) + *error = 0; + if (session == NULL) { + if (error != NULL) + *error = EINVAL; + return (NULL); + } + s_len = sdp_get_length(session); + ret = malloc(s_len + 1); + if (ret == NULL) { + if (error != NULL) + *error = ENOMEM; + return (NULL); + } + buf = ret; + len = s_len + 1; + wrote = snprintf(buf, len, "v=%d%s", session->s_version, COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + origin = session->s_origin; + if (origin != NULL) { + wrote = snprintf(buf, len, "o=%s %llu %llu %s %s %s%s", + origin->o_username, origin->o_id, origin->o_version, + origin->o_nettype, origin->o_addrtype, origin->o_address, + COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + } + if (session->s_name != NULL) { + wrote = snprintf(buf, len, "s=%s%s", session->s_name, + COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + } + SDP_INFORMATION_TO_STR(session->s_info); + if (session->s_uri != NULL) { + wrote = snprintf(buf, len, "u=%s%s", session->s_uri, + COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + } + list = session->s_email; + while (list != NULL) { + wrote = snprintf(buf, len, "e=%s%s", (char *)list->value, + COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + list = list->next; + } + list = session->s_phone; + while (list != NULL) { + wrote = snprintf(buf, len, "p=%s%s", (char *)list->value, + COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + list = list->next; + } + conn = session->s_conn; + SDP_CONNECTION_TO_STR(conn); + bw = session->s_bw; + SDP_BANDWIDTH_TO_STR(bw); + time = session->s_time; + while (time != NULL) { + wrote = snprintf(buf, len, "t=%llu %llu%s", time->t_start, + time->t_stop, COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + repeat = time->t_repeat; + while (repeat != NULL) { + wrote = snprintf(buf, len, "r=%llu %llu", repeat-> + r_interval, repeat->r_duration); + len = len - wrote; + buf = buf + wrote; + list = repeat->r_offset; + while (list != NULL) { + wrote = snprintf(buf, len, " %llu", + *(uint64_t *)list->value); + len = len - wrote; + buf = buf + wrote; + list = list->next; + } + wrote = snprintf(buf, len, "%s", COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + repeat = repeat->r_next; + } + time = time->t_next; + } + zone = session->s_zone; + if (zone != NULL) { + wrote = snprintf(buf, len, "z=%llu %s", zone->z_time, + zone->z_offset); + len = len - wrote; + buf = buf + wrote; + zone = zone->z_next; + while (zone != NULL) { + wrote = snprintf(buf, len, " %llu %s", zone->z_time, + zone->z_offset); + len = len - wrote; + buf = buf + wrote; + zone = zone->z_next; + } + wrote = snprintf(buf, len, "%s", COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + } + SDP_KEY_TO_STR(session->s_key); + attr = session->s_attr; + SDP_ATTR_TO_STR(attr); + media = session->s_media; + while (media != NULL) { + if (media->m_portcount == 1) { + wrote = snprintf(buf, len, "m=%s %d %s", media->m_name, + media->m_port, media->m_proto); + } else { + wrote = snprintf(buf, len, "m=%s %d/%d %s", media-> + m_name, media->m_port, media->m_portcount, media-> + m_proto); + } + len = len - wrote; + buf = buf + wrote; + list = media->m_format; + while (list != NULL) { + wrote = snprintf(buf, len, " %s", (char *)list->value); + len = len - wrote; + buf = buf + wrote; + list = list->next; + } + wrote = snprintf(buf, len, "%s", COMMP_CRLF); + len = len - wrote; + buf = buf + wrote; + SDP_INFORMATION_TO_STR(media->m_info); + conn = media->m_conn; + SDP_CONNECTION_TO_STR(conn); + bw = media->m_bw; + SDP_BANDWIDTH_TO_STR(bw); + SDP_KEY_TO_STR(media->m_key); + attr = media->m_attr; + SDP_ATTR_TO_STR(attr); + media = media->m_next; + } + assert(len >= 1); + *buf = '\0'; + return (ret); +} + +/* + * Given a session structure and the field ('v', 'o', 's', et al), this API + * deletes the corresponding structure element. It frees the memory and sets the + * pointer to NULL + */ +int +sdp_delete_all_field(sdp_session_t *session, const char field) +{ + if (session == NULL) + return (EINVAL); + switch (field) { + case SDP_ORIGIN_FIELD: + sdp_free_origin(session->s_origin); + session->s_origin = NULL; + break; + case SDP_NAME_FIELD: + free(session->s_name); + session->s_name = NULL; + break; + case SDP_INFO_FIELD: + free(session->s_info); + session->s_info = NULL; + break; + case SDP_URI_FIELD: + free(session->s_uri); + session->s_uri = NULL; + break; + case SDP_EMAIL_FIELD: + sdp_free_list(session->s_email); + session->s_email = NULL; + break; + case SDP_PHONE_FIELD: + sdp_free_list(session->s_phone); + session->s_phone = NULL; + break; + case SDP_CONNECTION_FIELD: + sdp_free_connection(session->s_conn); + session->s_conn = NULL; + break; + case SDP_BANDWIDTH_FIELD: + sdp_free_bandwidth(session->s_bw); + session->s_bw = NULL; + break; + case SDP_TIME_FIELD: + sdp_free_time(session->s_time); + session->s_time = NULL; + break; + case SDP_ZONE_FIELD: + sdp_free_zone(session->s_zone); + session->s_zone = NULL; + break; + case SDP_KEY_FIELD: + sdp_free_key(session->s_key); + session->s_key = NULL; + break; + case SDP_ATTRIBUTE_FIELD: + sdp_free_attribute(session->s_attr); + session->s_attr = NULL; + break; + case SDP_MEDIA_FIELD: + sdp_free_media(session->s_media); + session->s_media = NULL; + break; + default: + return (EINVAL); + } + return (0); +} + +/* + * Given a media structure and the field ('i', 'b', 'c', et al), this API + * deletes the corresponding structure element. It frees the memory and sets + * the pointer to NULL. + */ +int +sdp_delete_all_media_field(sdp_media_t *media, const char field) +{ + if (media == NULL) + return (EINVAL); + switch (field) { + case SDP_INFO_FIELD: + free(media->m_info); + media->m_info = NULL; + break; + case SDP_CONNECTION_FIELD: + sdp_free_connection(media->m_conn); + media->m_conn = NULL; + break; + case SDP_BANDWIDTH_FIELD: + sdp_free_bandwidth(media->m_bw); + media->m_bw = NULL; + break; + case SDP_KEY_FIELD: + sdp_free_key(media->m_key); + media->m_key = NULL; + break; + case SDP_ATTRIBUTE_FIELD: + sdp_free_attribute(media->m_attr); + media->m_attr = NULL; + break; + default: + return (EINVAL); + } + return (0); +} + +/* + * Given a media list and the media, this API deletes that media from the + * list. It frees the memory corresponding to that media. + */ +int +sdp_delete_media(sdp_media_t **l_media, sdp_media_t *media) +{ + sdp_media_t *cur; + sdp_media_t *prev; + + if (l_media == NULL || *l_media == NULL || media == NULL) + return (EINVAL); + cur = *l_media; + prev = NULL; + while (cur != NULL && cur != media) { + prev = cur; + cur = cur->m_next; + } + if (cur == NULL) + return (EINVAL); + if (cur == *l_media) + *l_media = cur->m_next; + else + prev->m_next = cur->m_next; + cur->m_next = NULL; + sdp_free_media(cur); + return (0); +} + +/* + * Given an attribute list and an attribute, this API deletes that attribue + * from the list. It frees the memory corresponding to that attribute. + */ +int +sdp_delete_attribute(sdp_attr_t **l_attr, sdp_attr_t *attr) +{ + sdp_attr_t *cur; + sdp_attr_t *prev; + + if (l_attr == NULL || *l_attr == NULL || attr == NULL) + return (EINVAL); + cur = *l_attr; + prev = NULL; + while (cur != NULL && cur != attr) { + prev = cur; + cur = cur->a_next; + } + if (cur == NULL) + return (EINVAL); + if (cur == *l_attr) + *l_attr = cur->a_next; + else + prev->a_next = cur->a_next; + cur->a_next = NULL; + sdp_free_attribute(cur); + return (0); +} + +/* + * Allocates a new sdp session structure and assigns a version number to it. + * Currently one version is defined and it is 1. This will be useful in future + * in the unlikely need to change the structure. + */ +sdp_session_t * +sdp_new_session() +{ + sdp_session_t *session = NULL; + + session = calloc(1, sizeof (sdp_session_t)); + if (session != NULL) + session->sdp_session_version = SDP_SESSION_VERSION_1; + return (session); +} diff --git a/usr/src/lib/libcommputil/common/sdp.h b/usr/src/lib/libcommputil/common/sdp.h new file mode 100644 index 0000000000..8c375a8ee1 --- /dev/null +++ b/usr/src/lib/libcommputil/common/sdp.h @@ -0,0 +1,254 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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. + */ + +#ifndef _SDP_H +#define _SDP_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define SDP_VERSION_FIELD 'v' +#define SDP_ORIGIN_FIELD 'o' +#define SDP_NAME_FIELD 's' +#define SDP_INFO_FIELD 'i' +#define SDP_URI_FIELD 'u' +#define SDP_EMAIL_FIELD 'e' +#define SDP_PHONE_FIELD 'p' +#define SDP_CONNECTION_FIELD 'c' +#define SDP_BANDWIDTH_FIELD 'b' +#define SDP_TIME_FIELD 't' +#define SDP_REPEAT_FIELD 'r' +#define SDP_ZONE_FIELD 'z' +#define SDP_KEY_FIELD 'k' +#define SDP_ATTRIBUTE_FIELD 'a' +#define SDP_MEDIA_FIELD 'm' + +/* SDP Parse errors */ +#define SDP_VERSION_ERROR 0x00000001 +#define SDP_ORIGIN_ERROR 0x00000002 +#define SDP_NAME_ERROR 0x00000004 +#define SDP_INFO_ERROR 0x00000008 +#define SDP_URI_ERROR 0x00000010 +#define SDP_EMAIL_ERROR 0x00000020 +#define SDP_PHONE_ERROR 0x00000040 +#define SDP_CONNECTION_ERROR 0x00000080 +#define SDP_BANDWIDTH_ERROR 0x00000100 +#define SDP_TIME_ERROR 0x00000200 +#define SDP_REPEAT_TIME_ERROR 0x00000400 +#define SDP_ZONE_ERROR 0x00000800 +#define SDP_KEY_ERROR 0x00001000 +#define SDP_ATTRIBUTE_ERROR 0x00002000 +#define SDP_MEDIA_ERROR 0x00004000 +#define SDP_FIELDS_ORDER_ERROR 0x00008000 +#define SDP_MISSING_FIELDS 0x00010000 + +#define SDP_AUDIO "audio" +#define SDP_VIDEO "video" +#define SDP_TEXT "text" +#define SDP_APPLICATION "application" +#define SDP_MESSAGE "message" +#define SDP_RTPMAP "rtpmap" + +#define SDP_SESSION_VERSION_1 1 + +typedef struct sdp_list { + void *value; + struct sdp_list *next; +} sdp_list_t; + +/* + * SDP origin field. + * o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address> + */ +typedef struct sdp_origin { + char *o_username; + uint64_t o_id; + uint64_t o_version; + char *o_nettype; + char *o_addrtype; + char *o_address; +} sdp_origin_t; + +/* + * SDP connection field. + * c=<nettype> <addrtype> <connection-address>[/ttl]/<number of addresses> + */ +typedef struct sdp_conn { + char *c_nettype; + char *c_addrtype; + char *c_address; + int c_addrcount; + struct sdp_conn *c_next; + uint8_t c_ttl; +} sdp_conn_t; + +/* + * SDP repeat field. Always found in time structure. + * r=<repeat interval> <active duration> <offsets from start-time> + */ +typedef struct sdp_repeat { + uint64_t r_interval; + uint64_t r_duration; + sdp_list_t *r_offset; + struct sdp_repeat *r_next; +} sdp_repeat_t; + +/* + * SDP time field. + * t=<start-time> <stop-time> + */ +typedef struct sdp_time { + uint64_t t_start; + uint64_t t_stop; + sdp_repeat_t *t_repeat; + struct sdp_time *t_next; +} sdp_time_t; + +/* + * SDP time zone field. + * z=<adjustment time> <offset> <adjustment time> <offset> .... + */ +typedef struct sdp_zone { + uint64_t z_time; + char *z_offset; + struct sdp_zone *z_next; +} sdp_zone_t; + +/* + * SDP attribute field. + * a=<attribute> or a=<attribute>:<value> + */ +typedef struct sdp_attr { + char *a_name; + char *a_value; + struct sdp_attr *a_next; +} sdp_attr_t; + +/* + * SDP bandwidth field. + * b=<bwtype>:<bandwidth> + */ +typedef struct sdp_bandwidth { + char *b_type; + uint64_t b_value; + struct sdp_bandwidth *b_next; +} sdp_bandwidth_t; + +/* + * SDP key field to session or media section of SDP. + * k=<method> or k=<method>:<encryption key> + */ +typedef struct sdp_key { + char *k_method; + char *k_enckey; +} sdp_key_t; + +typedef struct sdp_session sdp_session_t; + +/* + * SDP media section, contains media fields and other fields within + * media section. + * m=<media> <port>[/portcount] <proto> <fmt> ... + */ +typedef struct sdp_media { + char *m_name; + uint_t m_port; + int m_portcount; + char *m_proto; + sdp_list_t *m_format; + char *m_info; + sdp_conn_t *m_conn; + sdp_bandwidth_t *m_bw; + sdp_key_t *m_key; + sdp_attr_t *m_attr; + struct sdp_media *m_next; + sdp_session_t *m_session; +} sdp_media_t; + +struct sdp_session { + int sdp_session_version; + int s_version; + sdp_origin_t *s_origin; + char *s_name; + char *s_info; + char *s_uri; + sdp_list_t *s_email; + sdp_list_t *s_phone; + sdp_conn_t *s_conn; + sdp_bandwidth_t *s_bw; + sdp_time_t *s_time; + sdp_zone_t *s_zone; + sdp_key_t *s_key; + sdp_attr_t *s_attr; + sdp_media_t *s_media; +}; + +extern int sdp_parse(const char *, int, int, sdp_session_t **, + uint_t *); +extern sdp_media_t *sdp_find_media(sdp_media_t *, const char *); +extern sdp_attr_t *sdp_find_attribute(sdp_attr_t *, const char *); +extern sdp_attr_t *sdp_find_media_rtpmap(sdp_media_t *, const char *); +extern sdp_session_t *sdp_clone_session(const sdp_session_t *); +extern sdp_session_t *sdp_new_session(); +extern int sdp_add_origin(sdp_session_t *, const char *, uint64_t, + uint64_t, const char *, const char *, const char *); +extern int sdp_add_name(sdp_session_t *, const char *); +extern int sdp_add_information(char **, const char *); +extern int sdp_add_uri(sdp_session_t *, const char *); +extern int sdp_add_email(sdp_session_t *, const char *); +extern int sdp_add_phone(sdp_session_t *, const char *); +extern int sdp_add_connection(sdp_conn_t **, const char *, + const char *, const char *, uint8_t, int); +extern int sdp_add_bandwidth(sdp_bandwidth_t **, const char *, + uint64_t); +extern int sdp_add_repeat(sdp_time_t *, uint64_t, uint64_t, + const char *); +extern int sdp_add_time(sdp_session_t *, uint64_t, uint64_t, + sdp_time_t **); +extern int sdp_add_zone(sdp_session_t *, uint64_t, const char *); +extern int sdp_add_key(sdp_key_t **, const char *, const char *); +extern int sdp_add_attribute(sdp_attr_t **, const char *, + const char *); +extern int sdp_add_media(sdp_session_t *, const char *, uint_t, + int, const char *, const char *, sdp_media_t **); +extern int sdp_delete_all_field(sdp_session_t *, const char); +extern int sdp_delete_all_media_field(sdp_media_t *, const char); +extern int sdp_delete_media(sdp_media_t **, sdp_media_t *); +extern int sdp_delete_attribute(sdp_attr_t **, sdp_attr_t *); +extern void sdp_free_session(sdp_session_t *); +extern char *sdp_session_to_str(const sdp_session_t *, int *); + + +#ifdef __cplusplus +} +#endif + +#endif /* _SDP_H */ diff --git a/usr/src/lib/libcommputil/common/sdp_parse.c b/usr/src/lib/libcommputil/common/sdp_parse.c new file mode 100644 index 0000000000..8f4e2c0197 --- /dev/null +++ b/usr/src/lib/libcommputil/common/sdp_parse.c @@ -0,0 +1,1255 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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 +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; +} + +/* + * 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 +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; + } + /* there can be only one name field */ + 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; + } + } +} + +/* + * 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 +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; + } + /* There can be only one info field */ + 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; + } + } +} + +/* + * uri-field (u=) + * [%x75 "=" uri CRLF] + * anything between "=" and "CRLF" is considered to be URI. + */ +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; + } + /* There can be only one uri field */ + 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; + } + } +} + +/* + * phone-fields (p=) + * *(%x70 "=" phone-number CRLF) + * anything between "=" and "CRLF" is considered to be phone-number + */ +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; + } + } +} + +/* + * email-fields (e=) + * *(%x65 "=" email-address CRLF) + * anything between "=" and "CRLF" is considered to be email-address + */ +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; + } + } +} + +/* + * 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 +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; + } + /* There can be only one origin field */ + if (*origin != NULL) + return; + new_origin = calloc(1, sizeof (sdp_origin_t)); + if (new_origin == NULL) { + *p_error |= SDP_MEMORY_ERROR; + return; + } + /* Get username */ + 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; + } + } + /* Get Session-ID */ + 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; + /* Get Version */ + 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; + /* Get nettype */ + 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; + } + } + /* Get addrtype */ + 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; + } + } + /* Get address. Its the last sub-field */ + 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); +} + +/* + * 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 * +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); + } + /* Get start-time */ + 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; + /* Get stop-time */ + 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; + /* Now assign time to session structure */ + 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); +} + +/* + * 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 +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; + } + /* Get NetworkType */ + 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; + } + } + /* Get AddressType */ + 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; + } + /* Get Address. Parsing depends if its IP4,IP6 or something else */ + 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) { + /* SLASH is present. Needs further parsing */ + 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) { + /* + * 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 { + 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); +} + +/* + * bandwidth-fields (b=) + * *(%x62 "=" bwtype ":" bandwidth CRLF) + * bwtype = token + * bandwidth = 1*DIGIT + */ +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); +} + +/* + * 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 +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; + } + /* + * 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. + */ + if (time == NULL) + return; + /* + * Get the latest time field and associate this repeat field + * with it. + */ + 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; + } + /* + * for a given time field, there could be several repeat fields + * add the new repeat field at the end of it. + */ + 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; + } + /* + * Populate the elements of sdp_repeat. + * Get time-interval + */ + 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; + /* Get duration. It could be the last sub-field */ + 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; + /* Get offsets into sdp_list */ + 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; + } + /* check for trailing white space character. */ + 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); +} + +/* + * zone-adjustments (z=) + * %x7a "=" time SP ["-"] typed-time *(SP time SP ["-"] typed-time) + */ +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; + } + /* There can be atmost one zone field. */ + if (*zone != NULL) + return; + /* Get time and offset */ + 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; +} + +/* + * 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 +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; + } + /* There can be only one key field */ + if (*key != NULL) + return; + new_key = calloc(1, sizeof (sdp_key_t)); + if (new_key == NULL) { + *p_error |= SDP_MEMORY_ERROR; + return; + } + /* Get Method name */ + 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; + } + } + /* Get key, if exists. */ + 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); +} + +/* + * attribute-fields (a=) + * *(%x61 "=" attribute CRLF) + * attribute = (att-field ":" att-value) / att-field + * att-field = token + * att-value = byte-string + */ +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; + } + /* Get Attribute Name */ + 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; + } + } + /* Get Attribute Value */ + 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); +} + +/* + * media-field (m=) + * %x6d "=" media SP port ["/" integer] SP proto 1*(SP fmt) CRLF + */ +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; + /* Get media name */ + 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); + } + } + /* Get port */ + 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; + /* Get portcount */ + 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; + } + /* Get Protocol */ + 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; + /* Get format list */ + 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; + } + /* check for trailing white space character. */ + if (isspace(*(end - 1))) + goto err_ret; + /* Assign new media to the media list */ + 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); +} + +/* + * 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 +sdp_check_order(char prev, char *order, int *error) +{ + *error = 0; + while (*order != '\0') { + if (*order++ == prev) + 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 +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; /* fields order error */ + 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 { + /* + * RFC - 4566 says that session section should + * have only one connection field, while media + * section can have many + */ + 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; + /* we pass time, as repeat is associated with time */ + 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: + /* Unknown field type. Ignore it */ + 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; + } +} + +/* + * Parses the SDP info + */ +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); + } + /* Needed later to check for mandatory fields */ + 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)) { + /* + * RFC says parser SHOULD be tolerant to records ending + * with a single newline character too. + */ + 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); + } + /* + * 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 + */ + 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); +} diff --git a/usr/src/lib/libcommputil/common/sdp_parse.h b/usr/src/lib/libcommputil/common/sdp_parse.h new file mode 100644 index 0000000000..19562dc29c --- /dev/null +++ b/usr/src/lib/libcommputil/common/sdp_parse.h @@ -0,0 +1,107 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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. + */ + +#ifndef _SDP_PARSE_H +#define _SDP_PARSE_H + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sdp.h> +#include <sys/types.h> + +#define SDP_MEMORY_ERROR 0x10000000 + +#define SDP_VERSION_ORDER " " +#define SDP_ORIGIN_ORDER "v" +#define SDP_NAME_ORDER "o" +#define SDP_INFO_ORDER "s" +#define SDP_URI_ORDER "is" +#define SDP_EMAIL_ORDER "euis" +#define SDP_PHONE_ORDER "peuis" +#define SDP_CONN_ORDER "peuis" +#define SDP_BW_ORDER "bcpeuis" +#define SDP_TIME_ORDER "tbcpeuis" +#define SDP_REPEAT_ORDER "rt" +#define SDP_ZONE_ORDER "rt" +#define SDP_KEY_ORDER "zrt" +#define SDP_ATTR_ORDER "akzrt" +#define SDP_MEDIA_ORDER "makzrt" +#define SDP_M_INFO_ORDER "m" +#define SDP_M_CONN_ORDER "cim" +#define SDP_M_BW_ORDER "bcim" +#define SDP_M_KEY_ORDER "bcim" +#define SDP_M_ATTR_ORDER "akbcim" + +typedef struct sdp_description { + /* + * Following boolean fields are used to + * check for presence of mandatory fields + * in session structure + */ + boolean_t d_version; /* Version field */ + boolean_t d_origin; /* Origin field */ + boolean_t d_name; /* Name field */ + boolean_t d_conn; /* Connection field */ + boolean_t d_mconn; /* Media connection field */ + boolean_t d_mparsed; /* Media parsed */ + boolean_t d_tparsed; /* Time parsed */ + /* + * keeps count of connection fields within + * media section + */ + int d_mccount; + sdp_media_t *d_lmedia; /* Last media field */ + sdp_time_t *d_ltime; /* Last time field */ + uint_t d_perror; /* Parse error */ + char d_prev; /* previous field */ + char d_mprev; /* previous field in media section */ +} sdp_description_t; + +extern int add_value_to_list(sdp_list_t **, const char *, int, + boolean_t); +extern int sdp_list_to_str(sdp_list_t *, char **, boolean_t); +extern int sdp_str_to_list(sdp_list_t **, const char *, int, + boolean_t); +extern void sdp_free_repeat(sdp_repeat_t *); +extern void sdp_free_origin(sdp_origin_t *); +extern void sdp_free_list(sdp_list_t *); +extern void sdp_free_connection(sdp_conn_t *); +extern void sdp_free_bandwidth(sdp_bandwidth_t *); +extern void sdp_free_time(sdp_time_t *); +extern void sdp_free_zone(sdp_zone_t *); +extern void sdp_free_attribute(sdp_attr_t *); +extern void sdp_free_key(sdp_key_t *); +extern void sdp_free_media(sdp_media_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _SDP_PARSE_H */ diff --git a/usr/src/lib/libcommputil/common/sdp_parse_helper.c b/usr/src/lib/libcommputil/common/sdp_parse_helper.c new file mode 100644 index 0000000000..ee7ab406fb --- /dev/null +++ b/usr/src/lib/libcommputil/common/sdp_parse_helper.c @@ -0,0 +1,367 @@ +/* + * 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 + * or http://www.opensolaris.org/os/licensing. + * 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" + +/* + * Helper functions to skip white spaces, find tokens, find separators and free + * memory. + */ + +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <sdp.h> + +#include "sdp_parse.h" +#include "commp_util.h" + +void +sdp_free_origin(sdp_origin_t *origin) +{ + if (origin != NULL) { + if (origin->o_username != NULL) + free(origin->o_username); + if (origin->o_nettype != NULL) + free(origin->o_nettype); + if (origin->o_addrtype != NULL) + free(origin->o_addrtype); + if (origin->o_address != NULL) + free(origin->o_address); + free(origin); + } +} + +void +sdp_free_key(sdp_key_t *key) +{ + if (key != NULL) { + if (key->k_method != NULL) + free(key->k_method); + if (key->k_enckey != NULL) + free(key->k_enckey); + free(key); + } +} + +void +sdp_free_zone(sdp_zone_t *zone) +{ + sdp_zone_t *next_zone; + + while (zone != NULL) { + next_zone = zone->z_next; + if (zone->z_offset != NULL) + free(zone->z_offset); + free(zone); + zone = next_zone; + } +} + +void +sdp_free_list(sdp_list_t *list) +{ + sdp_list_t *next_list; + + while (list != NULL) { + next_list = list->next; + if (list->value != NULL) + free(list->value); + free(list); + list = next_list; + } +} + +void +sdp_free_media(sdp_media_t *media) +{ + sdp_media_t *next_media; + + while (media != NULL) { + next_media = media->m_next; + if (media->m_name != NULL) + free(media->m_name); + if (media->m_proto != NULL) + free(media->m_proto); + if (media->m_format != NULL) + sdp_free_list(media->m_format); + if (media->m_info != NULL) + free(media->m_info); + if (media->m_conn != NULL) + sdp_free_connection(media->m_conn); + if (media->m_bw != NULL) + sdp_free_bandwidth(media->m_bw); + if (media->m_key != NULL) + sdp_free_key(media->m_key); + if (media->m_attr != NULL) + sdp_free_attribute(media->m_attr); + free(media); + media = next_media; + } +} + +void +sdp_free_attribute(sdp_attr_t *attr) +{ + sdp_attr_t *next_attr; + + while (attr != NULL) { + next_attr = attr->a_next; + if (attr->a_name != NULL) + free(attr->a_name); + if (attr->a_value != NULL) + free(attr->a_value); + free(attr); + attr = next_attr; + } +} + +void +sdp_free_connection(sdp_conn_t *conn) +{ + sdp_conn_t *next_conn; + + while (conn != NULL) { + next_conn = conn->c_next; + if (conn->c_nettype != NULL) + free(conn->c_nettype); + if (conn->c_addrtype != NULL) + free(conn->c_addrtype); + if (conn->c_address != NULL) + free(conn->c_address); + free(conn); + conn = next_conn; + } +} + +void +sdp_free_bandwidth(sdp_bandwidth_t *bw) +{ + sdp_bandwidth_t *next_bw; + + while (bw != NULL) { + next_bw = bw->b_next; + if (bw->b_type != NULL) + free(bw->b_type); + free(bw); + bw = next_bw; + } +} + +void +sdp_free_repeat(sdp_repeat_t *repeat) +{ + sdp_repeat_t *next_repeat; + + while (repeat != NULL) { + next_repeat = repeat->r_next; + sdp_free_list(repeat->r_offset); + free(repeat); + repeat = next_repeat; + } +} + +void +sdp_free_time(sdp_time_t *time) +{ + sdp_time_t *next_time; + + while (time != NULL) { + next_time = time->t_next; + sdp_free_repeat(time->t_repeat); + free(time); + time = next_time; + } +} + +void +sdp_free_session(sdp_session_t *session) +{ + if (session == NULL) + return; + if (session->s_origin != NULL) + sdp_free_origin(session->s_origin); + if (session->s_name != NULL) + free(session->s_name); + if (session->s_info != NULL) + free(session->s_info); + if (session->s_uri != NULL) + free(session->s_uri); + if (session->s_email != NULL) + sdp_free_list(session->s_email); + if (session->s_phone != NULL) + sdp_free_list(session->s_phone); + if (session->s_conn != NULL) + sdp_free_connection(session->s_conn); + if (session->s_bw != NULL) + sdp_free_bandwidth(session->s_bw); + if (session->s_time != NULL) + sdp_free_time(session->s_time); + if (session->s_zone != NULL) + sdp_free_zone(session->s_zone); + if (session->s_key != NULL) + sdp_free_key(session->s_key); + if (session->s_attr != NULL) + sdp_free_attribute(session->s_attr); + if (session->s_media != NULL) + sdp_free_media(session->s_media); + free(session); +} + +/* + * Adds text of a given length to a linked list. If the list is NULL to + * start with it builds the new list + */ +int +add_value_to_list(sdp_list_t **list, const char *value, int len, boolean_t text) +{ + sdp_list_t *new = NULL; + sdp_list_t *tmp = NULL; + + new = malloc(sizeof (sdp_list_t)); + if (new == NULL) + return (ENOMEM); + new->next = NULL; + if (text) + new->value = (char *)calloc(1, len + 1); + else + new->value = (uint64_t *)calloc(1, sizeof (uint64_t)); + if (new->value == NULL) { + free(new); + return (ENOMEM); + } + if (text) { + (void) strncpy(new->value, value, len); + } else { + if (commp_time_to_secs((char *)value, (char *)(value + + len), new->value) != 0) { + sdp_free_list(new); + return (EINVAL); + } + } + if (*list == NULL) { + *list = new; + } else { + tmp = *list; + while (tmp->next != NULL) + tmp = tmp->next; + tmp->next = new; + } + return (0); +} + +/* + * Given a linked list converts it to space separated string. + */ +int +sdp_list_to_str(sdp_list_t *list, char **buf, boolean_t text) +{ + int size = 0; + int wrote = 0; + sdp_list_t *tmp; + char *ret; + char c[1]; + + if (list == NULL) { + *buf = NULL; + return (EINVAL); + } + tmp = list; + while (list != NULL) { + if (text) + size += strlen((char *)list->value); + else + size += snprintf(c, 1, "%lld", + *(uint64_t *)list->value); + size++; + list = list->next; + } + list = tmp; + if (size > 0) { + *buf = calloc(1, size + 1); + if (*buf == NULL) + return (ENOMEM); + ret = *buf; + while (list != NULL) { + if (text) { + wrote = snprintf(ret, size, "%s ", + (char *)list->value); + } else { + wrote = snprintf(ret, size, "%lld ", + *(uint64_t *)list->value); + } + ret = ret + wrote; + size = size - wrote; + list = list->next; + } + } else { + return (EINVAL); + } + return (0); +} + +/* + * Given a space separated string, converts it into linked list. SDP field + * repeat and media can have undefined number of offsets or formats + * respectively. We need to capture it in a linked list. + */ +int +sdp_str_to_list(sdp_list_t **list, const char *buf, int len, boolean_t text) +{ + const char *begin; + const char *current; + const char *end; + int ret = 0; + + if (len == 0) + return (EINVAL); + current = buf; + end = current + len; + /* takes care of strings with just spaces */ + if (commp_skip_white_space(¤t, end) != 0) + return (EINVAL); + while (current < end) { + (void) commp_skip_white_space(¤t, end); + begin = current; + while (current < end) { + if (isspace(*current)) + break; + ++current; + } + if (current != begin) { + if ((ret = add_value_to_list(list, begin, + current - begin, text)) != 0) { + sdp_free_list(*list); + *list = NULL; + return (ret); + } + } + } + return (0); +} diff --git a/usr/src/lib/libcommputil/i386/Makefile b/usr/src/lib/libcommputil/i386/Makefile new file mode 100644 index 0000000000..3a2e1d517e --- /dev/null +++ b/usr/src/lib/libcommputil/i386/Makefile @@ -0,0 +1,29 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libcommputil/sparc/Makefile b/usr/src/lib/libcommputil/sparc/Makefile new file mode 100644 index 0000000000..3a2e1d517e --- /dev/null +++ b/usr/src/lib/libcommputil/sparc/Makefile @@ -0,0 +1,29 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com + +install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT) diff --git a/usr/src/lib/libcommputil/sparcv9/Makefile b/usr/src/lib/libcommputil/sparcv9/Makefile new file mode 100644 index 0000000000..b5538941d1 --- /dev/null +++ b/usr/src/lib/libcommputil/sparcv9/Makefile @@ -0,0 +1,30 @@ +# +# 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 +# or http://www.opensolaris.org/os/licensing. +# 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. +# +# ident "%Z%%M% %I% %E% SMI" +# + +include ../Makefile.com +include ../../Makefile.lib.64 + +install: all $(ROOTLIBS64) $(ROOTLINKS64) diff --git a/usr/src/pkgdefs/SUNWarc/prototype_com b/usr/src/pkgdefs/SUNWarc/prototype_com index 63332ac331..af8355f2b0 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_com +++ b/usr/src/pkgdefs/SUNWarc/prototype_com @@ -84,6 +84,8 @@ f none usr/lib/llib-lcrypt 644 root bin f none usr/lib/llib-lcrypt.ln 644 root bin f none usr/lib/llib-lcfgadm 644 root bin f none usr/lib/llib-lcfgadm.ln 644 root bin +f none usr/lib/llib-lcommputil 644 root bin +f none usr/lib/llib-lcommputil.ln 644 root bin s none usr/lib/llib-lcontract=../../lib/llib-lcontract s none usr/lib/llib-lcontract.ln=../../lib/llib-lcontract.ln s none usr/lib/llib-lctf=../../lib/llib-lctf diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386 index d44475eca0..1a1513926b 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_i386 +++ b/usr/src/pkgdefs/SUNWarc/prototype_i386 @@ -72,6 +72,7 @@ s none usr/lib/amd64/llib-lbsm.ln=../../../lib/amd64/llib-lbsm.ln s none usr/lib/amd64/llib-lpam.ln=../../../lib/amd64/llib-lpam.ln s none usr/lib/amd64/llib-lc.ln=../../../lib/amd64/llib-lc.ln f none usr/lib/amd64/llib-lcfgadm.ln 644 root bin +f none usr/lib/amd64/llib-lcommputil.ln 644 root bin s none usr/lib/amd64/llib-lcontract.ln=../../../lib/amd64/llib-lcontract.ln s none usr/lib/amd64/llib-lctf.ln=../../../lib/amd64/llib-lctf.ln f none usr/lib/amd64/llib-lcrypt.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWarc/prototype_sparc b/usr/src/pkgdefs/SUNWarc/prototype_sparc index 453df0720c..65ecb2c1cc 100644 --- a/usr/src/pkgdefs/SUNWarc/prototype_sparc +++ b/usr/src/pkgdefs/SUNWarc/prototype_sparc @@ -68,6 +68,7 @@ s none usr/lib/sparcv9/llib-lbsm.ln=../../../lib/sparcv9/llib-lbsm.ln s none usr/lib/sparcv9/llib-lpam.ln=../../../lib/sparcv9/llib-lpam.ln s none usr/lib/sparcv9/llib-lc.ln=../../../lib/sparcv9/llib-lc.ln f none usr/lib/sparcv9/llib-lcfgadm.ln 644 root bin +f none usr/lib/sparcv9/llib-lcommputil.ln 644 root bin s none usr/lib/sparcv9/llib-lcontract.ln=../../../lib/sparcv9/llib-lcontract.ln s none usr/lib/sparcv9/llib-lctf.ln=../../../lib/sparcv9/llib-lctf.ln f none usr/lib/sparcv9/llib-lcrypt.ln 644 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_com b/usr/src/pkgdefs/SUNWcsl/prototype_com index 4a64fa0692..ba88abbe25 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_com +++ b/usr/src/pkgdefs/SUNWcsl/prototype_com @@ -88,6 +88,8 @@ f none usr/lib/libcfgadm.so.1 755 root bin s none usr/lib/libcmd.so=libcmd.so.1 f none usr/lib/libcmd.so.1 755 root bin s none usr/lib/libcmdutils.so.1=../../lib/libcmdutils.so.1 +s none usr/lib/libcommputil.so=./libcommputil.so.1 +f none usr/lib/libcommputil.so.1 755 root bin s none usr/lib/libcontract.so=../../lib/libcontract.so.1 s none usr/lib/libcontract.so.1=../../lib/libcontract.so.1 f none usr/lib/libcrle.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386 index 0b02c4a52e..9571de2a01 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_i386 +++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386 @@ -151,6 +151,8 @@ s none usr/lib/amd64/libcfgadm.so=libcfgadm.so.1 f none usr/lib/amd64/libcmd.so.1 755 root bin s none usr/lib/amd64/libcmd.so=libcmd.so.1 s none usr/lib/amd64/libcmdutils.so.1=../../../lib/amd64/libcmdutils.so.1 +f none usr/lib/amd64/libcommputil.so.1 755 root bin +s none usr/lib/amd64/libcommputil.so=libcommputil.so.1 s none usr/lib/amd64/libcontract.so.1=../../../lib/amd64/libcontract.so.1 s none usr/lib/amd64/libcontract.so=../../../lib/amd64/libcontract.so.1 f none usr/lib/amd64/libcrle.so.1 755 root bin diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_sparc b/usr/src/pkgdefs/SUNWcsl/prototype_sparc index 98c9296214..8cbccaab92 100644 --- a/usr/src/pkgdefs/SUNWcsl/prototype_sparc +++ b/usr/src/pkgdefs/SUNWcsl/prototype_sparc @@ -143,6 +143,8 @@ s none usr/lib/sparcv9/libcfgadm.so=libcfgadm.so.1 f none usr/lib/sparcv9/libcmd.so.1 755 root bin s none usr/lib/sparcv9/libcmd.so=libcmd.so.1 s none usr/lib/sparcv9/libcmdutils.so.1=../../../lib/sparcv9/libcmdutils.so.1 +f none usr/lib/sparcv9/libcommputil.so.1 755 root bin +s none usr/lib/sparcv9/libcommputil.so=libcommputil.so.1 f none usr/lib/sparcv9/libcrle.so.1 755 root bin f none usr/lib/sparcv9/libcryptoutil.so.1 755 root bin s none usr/lib/sparcv9/libcryptoutil.so=libcryptoutil.so.1 diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index 2d378de80d..727d760801 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -574,6 +574,7 @@ f none usr/include/rtld_db.h 644 root bin f none usr/include/sched.h 644 root bin f none usr/include/schedctl.h 644 root bin f none usr/include/sac.h 644 root bin +f none usr/include/sdp.h 644 root bin f none usr/include/sip.h 644 root bin d none usr/include/sasl 0755 root bin f none usr/include/sasl/prop.h 0644 root bin |