summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorgm209912 <none@none>2007-10-23 07:41:07 -0700
committergm209912 <none@none>2007-10-23 07:41:07 -0700
commita93a1f58a8763fa69172980b98e3d24720c1136e (patch)
tree655f8085f5cffb198cbf1f88202774900a5fbc0f /usr/src
parentf6517e58b2a51b48b9bb30aa3be64f6df58a31fc (diff)
downloadillumos-gate-a93a1f58a8763fa69172980b98e3d24720c1136e.tar.gz
PSARC 2007/566 Session Description Protocol
6607878 RFE: Session Description Library needed for SIP application developers and other SDP consumers
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.lint1
-rw-r--r--usr/src/lib/Makefile2
-rw-r--r--usr/src/lib/libcommputil/Makefile53
-rw-r--r--usr/src/lib/libcommputil/Makefile.com48
-rw-r--r--usr/src/lib/libcommputil/amd64/Makefile30
-rw-r--r--usr/src/lib/libcommputil/common/commp_util.c220
-rw-r--r--usr/src/lib/libcommputil/common/commp_util.h76
-rw-r--r--usr/src/lib/libcommputil/common/llib-lcommputil31
-rw-r--r--usr/src/lib/libcommputil/common/mapfile-vers58
-rw-r--r--usr/src/lib/libcommputil/common/sdp.c1299
-rw-r--r--usr/src/lib/libcommputil/common/sdp.h254
-rw-r--r--usr/src/lib/libcommputil/common/sdp_parse.c1255
-rw-r--r--usr/src/lib/libcommputil/common/sdp_parse.h107
-rw-r--r--usr/src/lib/libcommputil/common/sdp_parse_helper.c367
-rw-r--r--usr/src/lib/libcommputil/i386/Makefile29
-rw-r--r--usr/src/lib/libcommputil/sparc/Makefile29
-rw-r--r--usr/src/lib/libcommputil/sparcv9/Makefile30
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_i3861
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_sparc1
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_com2
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_sparc2
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_com1
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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, end, COMMP_SP,
+ B_TRUE) != 0) {
+ goto err_ret;
+ }
+ } else {
+ if (commp_find_token(&begin, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, 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, &current, end, COMMP_SP, B_FALSE) != 0)
+ goto err_ret;
+ fake_end = current;
+ current = begin;
+ if (commp_find_token(&begin, &current, 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, &current, 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, &current, 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, &current, 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(&current, 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(&current, 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(&current, end) != 0)
+ return (EINVAL);
+ while (current < end) {
+ (void) commp_skip_white_space(&current, 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