[svn-commits] kpfleming: branch kpfleming/sofiasdp r130954 - in /team/kpfleming/sofiasdp: ....

SVN commits to the Digium repositories svn-commits at lists.digium.com
Tue Jul 15 11:35:35 CDT 2008


Author: kpfleming
Date: Tue Jul 15 11:35:34 2008
New Revision: 130954

URL: http://svn.digium.com/view/asterisk?view=rev&rev=130954
Log:
an experiment to see if the SDP parser/generator from the sofia-sip library would be usable in chan_sip

Added:
    team/kpfleming/sofiasdp/
      - copied from r130949, trunk/
    team/kpfleming/sofiasdp/channels/sofia-sip/
    team/kpfleming/sofiasdp/channels/sofia-sip/config.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp.c   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp_print.c   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_addrinfo.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_alloc_stat.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_config.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_configure.h.in   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_errno.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_class.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tag_inline.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_tagarg.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/sofia-sip/su_types.h   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/su_alloc.c   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/su_strdup.c   (with props)
    team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/su/su_taglist.c   (with props)
Modified:
    team/kpfleming/sofiasdp/channels/Makefile
    team/kpfleming/sofiasdp/channels/chan_sip.c

Modified: team/kpfleming/sofiasdp/channels/Makefile
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/channels/Makefile?view=diff&rev=130954&r1=130949&r2=130954
==============================================================================
--- team/kpfleming/sofiasdp/channels/Makefile (original)
+++ team/kpfleming/sofiasdp/channels/Makefile Tue Jul 15 11:35:34 2008
@@ -102,8 +102,20 @@
 
 $(if $(filter chan_oss,$(EMBEDDED_MODS)),modules.link,chan_oss.so): console_video.o vgrabbers.o console_board.o
 
+$(if $(filter chan_sip,$(EMBEDDED_MODS)),modules.link,chan_sip.so): $(foreach m,sdp/sdp sdp/sdp_print sdp/sdp_parse su/su_alloc su/su_taglist su/su_strdup,sofia-sip/libsofia-sip-ua/$(m).o)
+
+chan_sip.o sofia-sip/libsofia-sip-ua/sdp/%.o: ASTCFLAGS+=-Isofia-sip -Isofia-sip/libsofia-sip-ua/su -Isofia-sip/libsofia-sip-ua/sdp
+
+sofia-sip/libsofia-sip-ua/su/%.o: ASTCFLAGS+=-Isofia-sip -Isofia-sip/libsofia-sip-ua/su -Isofia-sip/libsofia-sip-ua/sdp
+
+sofia-sip/libsofia-sip-ua/sdp/sdp.o: ASTCFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations
+
+sofia-sip/libsofia-sip-ua/sdp/sdp_print.o: ASTCFLAGS+=-Wno-missing-format-attribute
+
+sofia-sip/libsofia-sip-ua/sdp/sdp_parse.o: ASTCFLAGS+=-Wno-missing-format-attribute
+
+sofia-sip/libsofia-sip-ua/su/su_taglist.o: ASTCFLAGS+=-Wno-undef -Wno-missing-declarations -Wno-missing-prototypes
+
 chan_usbradio.o: ./xpmr/xpmr.c ./xpmr/xpmr.h ./xpmr/xpmr_coef.h
 
 chan_usbradio.so: LIBS+=-lusb -lasound
-
-

Modified: team/kpfleming/sofiasdp/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/channels/chan_sip.c?view=diff&rev=130954&r1=130949&r2=130954
==============================================================================
--- team/kpfleming/sofiasdp/channels/chan_sip.c (original)
+++ team/kpfleming/sofiasdp/channels/chan_sip.c Tue Jul 15 11:35:34 2008
@@ -1,4 +1,4 @@
- /*
+/*
  * Asterisk -- An open source telephony toolkit.
  *
  * Copyright (C) 1999 - 2006, Digium, Inc.
@@ -198,6 +198,9 @@
 #include "asterisk/ast_version.h"
 #include "asterisk/event.h"
 #include "asterisk/tcptls.h"
+
+#include "sofia-sip/config.h"
+#include "sofia-sip/sdp.h"
 
 #ifndef FALSE
 #define FALSE    0

Added: team/kpfleming/sofiasdp/channels/sofia-sip/config.h
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/channels/sofia-sip/config.h?view=auto&rev=130954
==============================================================================
--- team/kpfleming/sofiasdp/channels/sofia-sip/config.h (added)
+++ team/kpfleming/sofiasdp/channels/sofia-sip/config.h Tue Jul 15 11:35:34 2008
@@ -1,0 +1,15 @@
+#define LLU "%llu"
+
+#define LLI "%lli"
+
+#define MOD_ZU "%zu"
+
+#define longlong long long
+
+#define DOXYGEN_ONLY 0
+
+#define SU_HAVE_WINSOCK 0
+
+#define HAVE_FREE_NULL 0
+
+#define SU_HAVE_TAGSTACK 0

Propchange: team/kpfleming/sofiasdp/channels/sofia-sip/config.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/kpfleming/sofiasdp/channels/sofia-sip/config.h
------------------------------------------------------------------------------
    svn:keywords = Author ID Date Revision

Propchange: team/kpfleming/sofiasdp/channels/sofia-sip/config.h
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp.c
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp.c?view=auto&rev=130954
==============================================================================
--- team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp.c (added)
+++ team/kpfleming/sofiasdp/channels/sofia-sip/libsofia-sip-ua/sdp/sdp.c Tue Jul 15 11:35:34 2008
@@ -1,0 +1,1877 @@
+/*
+ * This file is part of the Sofia-SIP package
+ *
+ * Copyright (C) 2005 Nokia Corporation.
+ *
+ * Contact: Pekka Pessi <pekka.pessi at nokia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**@CFILE sdp.c Simple SDP interface.
+ *
+ * @author Pekka Pessi <Pekka.Pessi at nokia.com>
+ * @author Kai Vehmanen <kai.vehmanen at nokia.com>
+ *
+ * @date Created: Fri Feb 18 10:25:08 2000 ppessi
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include <sofia-sip/su_alloc.h>
+#include <sofia-sip/su_types.h>
+
+#include "sofia-sip/sdp.h"
+
+struct align { void  *_a; char _b; };
+
+#define ALIGN(v, n) ((n - (intptr_t)(v)) & (n - 1))
+#define STRUCT_ALIGN_  (sizeof(struct align) - offsetof(struct align, _b))
+#define STRUCT_ALIGN(v) ALIGN(v, sizeof(void *))
+#define ASSERT_STRUCT_ALIGN(p) \
+  (STRUCT_ALIGN(p) ? (void)assert(!"STRUCT_ALIGNED(" #p ")") : (void)0)
+
+const unsigned sdp_struct_align_ = sizeof(void *) - STRUCT_ALIGN_;
+
+#define STR_XTRA(rv, s)    ((s) ? rv += strlen((s)) + 1 : 0)
+#define PTR_XTRA(rv, p, f) \
+  ((p) ? (rv += STRUCT_ALIGN(rv) + f(p)) : 0)
+#define LST_XTRA(rv, l, f) \
+  ((l) ? (rv += STRUCT_ALIGN(rv) + list_xtra_all((xtra_f*)f, l)) : 0)
+
+
+#define STRUCT_DUP(p, dst, src) \
+  ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src));	\
+  ((*(int*)(src) >= (int)sizeof(*src)					\
+    ? (dst = memcpy((p), (src), sizeof(*src)))				\
+    : (dst = memcpy((p), (src), *(int*)(src))),				\
+    memset((p)+*(int*)(src), 0, sizeof(*src) - *(int*)(src))), \
+  ((p) += sizeof(*src)))
+
+#define STRUCT_DUP2(p, dst, src) \
+  ASSERT_STRUCT_ALIGN(p); assert(*(int*)(src) >= (int)sizeof(*src));	\
+  (dst = memcpy((p), (src), *(int*)(src)), ((p) += *(int*)(src)))
+
+#define STR_DUP(p, dst, src, m) \
+ ((src->m) ? ((dst->m) = strcpy((p), (src->m)), (p) += strlen((p)) + 1) \
+           : ((dst->m) = 0))
+#define PTR_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)), ((dup)(&(p), (src->m)))): 0)
+#define LST_DUP(p, dst, src, m, dup) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       list_dup_all((dup_f*)(dup), &(p), src->m)) : 0)
+#define MED_XTRA_EX(rv, l, c) \
+  ((l) ? (rv += STRUCT_ALIGN(rv) + media_xtra_ex(l, c)) : 0)
+#define MED_DUP_EX(p, dst, src, m, dst_c, src_c) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       media_dup_all(&(p), src->m, dst, dst_c, src_c)) : 0)
+
+#define MED_XTRA_ALL(rv, m) \
+  ((m) ? (rv += STRUCT_ALIGN(rv) + media_xtra_all(m)) : 0)
+#define MED_DUP_ALL(p, dst, src, m) \
+ ((dst->m) = (src->m)?((p += STRUCT_ALIGN(p)),\
+                       media_dup_all(&(p), src->m, dst)) : 0)
+
+typedef size_t xtra_f(void const *);
+typedef void *dup_f(char **bb, void const *src);
+
+static size_t list_xtra_all(xtra_f *xtra, void const *v);
+static void *list_dup_all(dup_f *dup, char **bb, void const *vsrc);
+
+static size_t session_xtra(sdp_session_t const *o); 
+static sdp_session_t *session_dup(char **pp, sdp_session_t const *o);
+
+static size_t origin_xtra(sdp_origin_t const *o); 
+static sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *o);
+
+static size_t connection_xtra(sdp_connection_t const *o); 
+static sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *o);
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *o); 
+static sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *o);
+
+static size_t time_xtra(sdp_time_t const *o); 
+static sdp_time_t *time_dup(char **pp, sdp_time_t const *o);
+
+static size_t repeat_xtra(sdp_repeat_t const *o); 
+static sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *o);
+
+static size_t zone_xtra(sdp_zone_t const *o); 
+static sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *o);
+
+static size_t key_xtra(sdp_key_t const *o); 
+static sdp_key_t *key_dup(char **pp, sdp_key_t const *o);
+
+static size_t attribute_xtra(sdp_attribute_t const *o); 
+static sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *o);
+
+static size_t list_xtra(sdp_list_t const *o); 
+static sdp_list_t *list_dup(char **pp, sdp_list_t const *o);
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *o); 
+static sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *o);
+
+static size_t media_xtra(sdp_media_t const *o);
+static sdp_media_t *media_dup(char **pp,
+			      sdp_media_t const *o,
+			      sdp_session_t *sdp);
+#ifdef nomore
+static size_t media_xtra_ex(sdp_media_t const *o,
+			  sdp_connection_t const *c);
+static sdp_media_t *media_dup_ex(char **pp,
+				  sdp_media_t const *o,
+				  sdp_session_t *sdp,
+				  sdp_connection_t *dst_c,
+				  sdp_connection_t const *src_c);
+#endif
+static size_t media_xtra_all(sdp_media_t const *o);
+static sdp_media_t *media_dup_all(char **pp,
+				  sdp_media_t const *o,
+				  sdp_session_t *sdp);
+
+
+/** Define a function body duplicating an SDP structure. */
+#define SDP_DUP(type, name) \
+  sdp_##type##_t *rv; size_t size; char *p, *end; \
+  if (!name) return NULL; \
+  size = type##_xtra(name); \
+  p = su_alloc(h, size); end = p + size; \
+  rv = type##_dup(&p, name); \
+  assert(p == end); \
+  return rv;
+
+/** Define a function body duplicating a list of SDP structures. */
+#define SDP_LIST_DUP(type, name) \
+  sdp_##type##_t *rv; size_t size; char *p, *end; \
+  if (!name) return NULL; \
+  size = list_xtra_all((xtra_f*)type##_xtra, name); \
+  rv = su_alloc(h, size); p = (char *)rv; end = p + size; \
+  list_dup_all((dup_f*)type##_dup, &p, name); \
+  assert(p == end); \
+  return rv;
+
+/**Duplicate an SDP origin description.
+ *
+ * The function sdp_origin_dup() duplicates (deeply copies) an SDP origin
+ * description @a o allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param o     SDP origin description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_origin_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_origin_t *sdp_origin_dup(su_home_t *h, sdp_origin_t const *o)
+{ 
+  SDP_DUP(origin, o);
+}
+
+/**Duplicate an SDP connection description.
+ *
+ * The function sdp_connection_dup() duplicates (deeply copies) an SDP
+ * connection description @a c allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param c     SDP connection description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_connection_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_connection_t *sdp_connection_dup(su_home_t *h, sdp_connection_t const *c)
+{ 
+  SDP_LIST_DUP(connection, c);
+}
+
+/**Duplicate an SDP bandwidth description.
+ *
+ * The function sdp_bandwidth_dup() duplicates (deeply copies) an SDP
+ * bandwidth description @a b allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param b     SDP bandwidth description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_bandwidth_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_bandwidth_t *sdp_bandwidth_dup(su_home_t *h, sdp_bandwidth_t const *b)
+{ 
+  SDP_LIST_DUP(bandwidth, b);
+}
+
+/**Duplicate an SDP time description.
+ *
+ * The function sdp_time_dup() duplicates (deeply copies) an SDP time
+ * description @a t allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param t  SDP time description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_time_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_time_t *sdp_time_dup(su_home_t *h, sdp_time_t const *t)
+{ 
+  SDP_LIST_DUP(time, t);
+}
+
+/**Duplicate an SDP repeat description.
+ *
+ * The function sdp_repeat_dup() duplicates (deeply copies) an SDP repeat
+ * description @a r allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param r  SDP repeat description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_repeat_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_repeat_t *sdp_repeat_dup(su_home_t *h, sdp_repeat_t const *r)
+{ 
+  SDP_DUP(repeat, r);
+}
+
+/**Duplicate an SDP zone description.
+ *
+ * The function sdp_zone_dup() duplicates (deeply copies) an SDP zone
+ * description @a z allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param z  SDP zone description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_zone_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_zone_t *sdp_zone_dup(su_home_t *h, sdp_zone_t const *z)
+{ 
+  SDP_DUP(zone, z);
+}
+
+/**Duplicate an SDP key description.
+ *
+ * The function sdp_key_dup() duplicates (deeply copies) an SDP key
+ * description @a k allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param k  SDP key description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_key_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_key_t *sdp_key_dup(su_home_t *h, sdp_key_t const *k)
+{ 
+  SDP_DUP(key, k);
+}
+
+/**Duplicate an SDP attribute list.
+ *
+ * The function sdp_attribute_dup() duplicates (deeply copies) an SDP
+ * attribute list @a a allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param a  SDP attribute description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_attribute_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_attribute_t *sdp_attribute_dup(su_home_t *h, sdp_attribute_t const *a)
+{ 
+  SDP_LIST_DUP(attribute, a);
+}
+
+/**Duplicate an SDP list of text.
+ *
+ * The function sdp_list_dup() duplicates (deeply copies) an SDP text
+ * list @a l allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param l  SDP list description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_list_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_list_t *sdp_list_dup(su_home_t *h, sdp_list_t const *l)
+{ 
+  SDP_LIST_DUP(list, l);
+}
+
+/**Duplicate an SDP rtpmap list.
+ *
+ * The function sdp_rtpmap_dup() duplicates (deeply copies) an SDP rtpmap
+ * list @a rm allocating memory using memory @a home.
+ *
+ * @param h  Memory home
+ * @param rm SDP rtpmap description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_rtpmap_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_rtpmap_t *sdp_rtpmap_dup(su_home_t *h, sdp_rtpmap_t const *rm)
+{ 
+  SDP_LIST_DUP(rtpmap, rm);
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup() duplicates (deeply copies) an SDP media
+ * description @a m allocating memory using memory @a home.
+ *
+ * @param h   Memory home
+ * @param m   SDP media description to be duplicated
+ * @param sdp SDP session description to which the newly allocated
+ *            media description is linked
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup(su_home_t *h, sdp_media_t const *m, 
+			   sdp_session_t *sdp)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra(m);
+  p = su_alloc(h, size); end = p + size;
+  rv = media_dup(&p, m, sdp);
+  assert(p == end);
+  return rv;
+}
+
+/**Duplicate an SDP media description.
+ *
+ * The function sdp_media_dup_all() duplicates (deeply copies) a list of SDP
+ * media descriptions @a m allocating memory using memory @a home.
+ *
+ * @param h     Memory home
+ * @param m     list of SDP media descriptions to be duplicated
+ * @param sdp   SDP session description to which the newly allocated
+ *              media descriptions are linked
+ *
+ * @return 
+ * If successful, a pointer to a newly allocated list of sdp_media_t
+ * structures is returned, otherwise NULL is returned.
+ */
+sdp_media_t *sdp_media_dup_all(su_home_t *h, sdp_media_t const *m, 
+			       sdp_session_t *sdp)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra_all(m);
+  p = su_alloc(h, size); end = p + size;
+  rv = media_dup_all(&p, m, sdp);
+  assert(p == end);
+  return rv;
+}
+
+#ifdef nomore			/* really deprecated */
+/**Duplicate media description with common address.
+ *
+ * This function is provided in order to avoid duplicate @c c= lines.  If
+ * the @c c= line in media description equals to @a src_c, it is not
+ * duplicated but replaced with @a dst_c instead.
+ *
+ * @param home  Memory home
+ * @param src   SDP media description to be duplicated
+ * @param sdp   SDP session description to which the newly allocated
+ *              media description is linked
+ * @param dst_c Connection description used instead of duplicate of @a src_c.
+ * @param src_c Connection description not to be duplicated
+
+ * @return 
+ * If successful, a pointer to newly allocated sdp_media_t structure is
+ * returned, otherwise NULL is returned.
+ *
+ * @deprecated
+ * This function is deprecated. Use sdp_media_dup() instead.
+ */
+sdp_media_t *sdp_media_dup_ex(su_home_t *home, 
+			      sdp_media_t const *src,
+			      sdp_session_t *sdp,
+			      sdp_connection_t *dst_c,
+			      sdp_connection_t const *src_c)
+{
+  sdp_media_t *rv; size_t size; char *p, *end;
+  size = media_xtra_all(src, src_c);
+  p = su_alloc(home, size); end = p + size;
+  rv = media_dup_all(&p, src, sdp, dst_c, src_c);
+  assert(p == end);
+  return rv;
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static size_t origin_xtra(sdp_origin_t const *o)
+{
+  size_t rv = sizeof(*o);
+  STR_XTRA(rv, o->o_username);
+  PTR_XTRA(rv, o->o_address, connection_xtra);
+  return rv;
+}
+
+static
+sdp_origin_t *origin_dup(char **pp, sdp_origin_t const *src)
+{
+  char *p;
+  sdp_origin_t *o;
+
+  p = *pp; 
+  STRUCT_DUP(p, o, src);
+  STR_DUP(p, o, src, o_username);
+  PTR_DUP(p, o, src, o_address, connection_dup);
+
+  assert((size_t)(p - *pp) == origin_xtra(src));
+  *pp = p;
+  return o;
+}
+
+static size_t connection_xtra(sdp_connection_t const *c)
+{
+  size_t rv = sizeof(*c);
+  STR_XTRA(rv, c->c_address);
+  return rv;
+}
+
+static
+sdp_connection_t *connection_dup(char **pp, sdp_connection_t const *src)
+{
+  char *p;
+  sdp_connection_t *c;
+
+  p = *pp; 
+  STRUCT_DUP(p, c, src); 
+  c->c_next = NULL;
+  STR_DUP(p, c, src, c_address);
+
+  assert((size_t)(p - *pp) == connection_xtra(src));
+  *pp = p;
+  return c;
+}
+
+static size_t bandwidth_xtra(sdp_bandwidth_t const *b)
+{
+  size_t rv = sizeof(*b);
+  STR_XTRA(rv, b->b_modifier_name);
+  return rv;
+}
+
+static
+sdp_bandwidth_t *bandwidth_dup(char **pp, sdp_bandwidth_t const *src)
+{
+  char *p;
+  sdp_bandwidth_t *b;
+
+  p = *pp;
+  STRUCT_DUP(p, b, src);
+  b->b_next = NULL;
+  STR_DUP(p, b, src, b_modifier_name);
+
+  assert((size_t)(p - *pp) == bandwidth_xtra(src));
+  *pp = p;
+  return b;
+}
+
+
+static size_t time_xtra(sdp_time_t const *t)
+{
+  size_t rv = sizeof(*t);
+  PTR_XTRA(rv, t->t_repeat, repeat_xtra);
+  PTR_XTRA(rv, t->t_zone, zone_xtra);
+  return rv;
+}
+
+static
+sdp_time_t *time_dup(char **pp, sdp_time_t const *src)
+{
+  char *p;
+  sdp_time_t *t;
+
+  p = *pp;
+  STRUCT_DUP(p, t, src);
+  t->t_next = NULL;
+  PTR_DUP(p, t, src, t_repeat, repeat_dup);
+  PTR_DUP(p, t, src, t_zone, zone_dup);
+
+  assert((size_t)(p - *pp) == time_xtra(src));
+  *pp = p;
+  return t;
+}
+
+
+static size_t repeat_xtra(sdp_repeat_t const *r)
+{
+  return (size_t)r->r_size;
+}
+
+static
+sdp_repeat_t *repeat_dup(char **pp, sdp_repeat_t const *src)
+{
+  char *p;
+  sdp_repeat_t *r;
+
+  p = *pp;
+  STRUCT_DUP2(p, r, src);
+
+  assert((size_t)(p - *pp) == repeat_xtra(src));
+  *pp = p;
+  return r;
+}
+
+
+static size_t zone_xtra(sdp_zone_t const *z)
+{
+  return z->z_size;
+}
+
+static
+sdp_zone_t *zone_dup(char **pp, sdp_zone_t const *src)
+{
+  char *p;
+  sdp_zone_t *z;
+
+  p = *pp;
+  STRUCT_DUP2(p, z, src);
+
+  assert((size_t)(p - *pp) == zone_xtra(src));
+  *pp = p;
+  return z;
+}
+
+
+static size_t key_xtra(sdp_key_t const *k)
+{
+  size_t rv = sizeof(*k);
+  STR_XTRA(rv, k->k_method_name);
+  STR_XTRA(rv, k->k_material);
+  return rv;
+}
+
+static
+sdp_key_t *key_dup(char **pp, sdp_key_t const *src)
+{
+  char *p;
+  sdp_key_t *k;
+
+  p = *pp;
+  STRUCT_DUP(p, k, src);
+  STR_DUP(p, k, src, k_method_name);
+  STR_DUP(p, k, src, k_material);
+
+  assert((size_t)(p - *pp) == key_xtra(src));
+  *pp = p;
+  return k;
+}
+
+
+static size_t attribute_xtra(sdp_attribute_t const *a)
+{
+  size_t rv = sizeof(*a);
+  STR_XTRA(rv, a->a_name);
+  STR_XTRA(rv, a->a_value);
+  return rv;
+}
+
+static
+sdp_attribute_t *attribute_dup(char **pp, sdp_attribute_t const *src)
+{
+  char *p;
+  sdp_attribute_t *a;
+
+  p = *pp;
+  STRUCT_DUP(p, a, src);
+  a->a_next = NULL;
+  STR_DUP(p, a, src, a_name);
+  STR_DUP(p, a, src, a_value);
+
+  assert((size_t)(p - *pp) == attribute_xtra(src));
+  *pp = p;
+  return a;
+}
+
+
+static size_t media_xtra(sdp_media_t const *m)
+{
+  size_t rv = sizeof(*m);
+
+  STR_XTRA(rv, m->m_type_name);
+  STR_XTRA(rv, m->m_proto_name);
+  LST_XTRA(rv, m->m_format, list_xtra);
+  LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+  STR_XTRA(rv, m->m_information);
+  LST_XTRA(rv, m->m_connections, connection_xtra);
+  LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+  PTR_XTRA(rv, m->m_key, key_xtra);
+  LST_XTRA(rv, m->m_attributes, attribute_xtra);
+  
+  return rv;
+}
+
+static
+sdp_media_t *media_dup(char **pp, 
+		       sdp_media_t const *src,
+		       sdp_session_t *sdp)
+{
+  char *p;
+  sdp_media_t *m;
+
+  p = *pp;
+  STRUCT_DUP(p, m, src);
+  m->m_next = NULL;
+
+  STR_DUP(p, m, src, m_type_name);
+  STR_DUP(p, m, src, m_proto_name);
+  LST_DUP(p, m, src, m_format, list_dup);
+  LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+  STR_DUP(p, m, src, m_information);
+  LST_DUP(p, m, src, m_connections, connection_dup);
+  LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+  PTR_DUP(p, m, src, m_key, key_dup);
+  LST_DUP(p, m, src, m_attributes, attribute_dup);
+
+  /* note! we must not implicitly use 'src->m_session' as it 
+           might point to a temporary session */
+  m->m_session = sdp;
+    
+  m->m_rejected = src->m_rejected; 
+  m->m_mode = src->m_mode;
+
+  assert((size_t)(p - *pp) == media_xtra(src));
+  *pp = p;
+  return m;
+}
+
+#ifdef nomore
+static
+int media_xtra_ex(sdp_media_t const *m, sdp_connection_t const *c)
+{
+  int rv = 0;
+
+  for (; m; m = m->m_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += sizeof(*m);
+
+    STR_XTRA(rv, m->m_type_name);
+    STR_XTRA(rv, m->m_proto_name);
+    LST_XTRA(rv, m->m_format, list_xtra);
+    LST_XTRA(rv, m->m_rtpmaps, rtpmap_xtra);
+    STR_XTRA(rv, m->m_information);
+    if (c != m->m_connections)
+      LST_XTRA(rv, m->m_connections, connection_xtra);
+    LST_XTRA(rv, m->m_bandwidths, bandwidth_xtra);
+    PTR_XTRA(rv, m->m_key, key_xtra);
+    LST_XTRA(rv, m->m_attributes, attribute_xtra);
+  }
+
+  return rv;
+}
+
+static
+sdp_media_t *media_dup_ex(char **pp, 
+			  sdp_media_t const *src,
+			  sdp_session_t *sdp,
+			  sdp_connection_t *dst_c,
+			  sdp_connection_t const *src_c)
+{
+  char *p;
+  sdp_media_t *retval = NULL, *m, **mm = &retval;
+  int xtra = media_xtra_ex(src, src_c);
+
+  p = *pp;
+
+  for (; src; src = src->m_next) {
+    p += STRUCT_ALIGN(p);
+    STRUCT_DUP(p, m, src);
+    m->m_next = NULL;
+
+    STR_DUP(p, m, src, m_type_name);
+    STR_DUP(p, m, src, m_proto_name);
+    LST_DUP(p, m, src, m_format, list_dup);
+    LST_DUP(p, m, src, m_rtpmaps, rtpmap_dup);
+    STR_DUP(p, m, src, m_information);
+    if (src_c != src->m_connections)
+      LST_DUP(p, m, src, m_connections, connection_dup);
+    else
+      m->m_connections = dst_c;
+    LST_DUP(p, m, src, m_bandwidths, bandwidth_dup);
+    PTR_DUP(p, m, src, m_key, key_dup);
+    LST_DUP(p, m, src, m_attributes, attribute_dup);
+    
+    /* note! we must not implicitly use 'src->m_session' as it 
+       might point to a temporary session */
+    m->m_session = sdp;
+    
+    m->m_rejected = src->m_rejected; 
+    m->m_mode = src->m_mode;
+
+    assert(m);
+    *mm = m; mm = &m->m_next;
+  }
+
+  assert(p - *pp == xtra);
+
+
+  *pp = p;
+
+  return retval;
+}
+#endif
+
+static size_t media_xtra_all(sdp_media_t const *m)
+{
+  size_t rv = 0;
+
+  for (; m; m = m->m_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += media_xtra(m);
+  }
+
+  return rv;
+}
+
+static
+sdp_media_t *media_dup_all(char **pp, 
+			   sdp_media_t const *src,
+			   sdp_session_t *sdp)
+{
+  char *p;
+  sdp_media_t *retval = NULL, *m, **mm = &retval;
+
+  p = *pp;
+
+  for (; src; src = src->m_next) {
+    p += STRUCT_ALIGN(p);
+    m = media_dup(&p, src, sdp);
+    assert(m);
+    *mm = m; mm = &m->m_next;
+  }
+
+  *pp = p;
+
+  return retval;
+}
+
+static size_t list_xtra(sdp_list_t const *l)
+{
+  size_t rv = sizeof(*l);
+  rv += strlen(l->l_text) + 1;
+  return rv;
+}
+
+static
+sdp_list_t *list_dup(char **pp, sdp_list_t const *src)
+{
+  char *p;
+  sdp_list_t *l;
+
+  p = *pp; 
+  STRUCT_DUP(p, l, src);
+  l->l_next = NULL;
+  STR_DUP(p, l, src, l_text);
+
+  assert((size_t)(p - *pp) == list_xtra(src));
+  *pp = p;
+  return l;
+}
+
+
+static size_t rtpmap_xtra(sdp_rtpmap_t const *rm)
+{
+  size_t rv = sizeof(*rm);
+  STR_XTRA(rv, rm->rm_encoding);
+  STR_XTRA(rv, rm->rm_params);
+  STR_XTRA(rv, rm->rm_fmtp);
+  return rv;
+}
+
+static
+sdp_rtpmap_t *rtpmap_dup(char **pp, sdp_rtpmap_t const *src)
+{
+  char *p;
+  sdp_rtpmap_t *rm;
+
+  p = *pp; 
+  STRUCT_DUP(p, rm, src);
+  rm->rm_next = NULL;
+  STR_DUP(p, rm, src, rm_encoding);
+  STR_DUP(p, rm, src, rm_params);
+  STR_DUP(p, rm, src, rm_fmtp);
+
+  assert((size_t)(p - *pp) == rtpmap_xtra(src));
+  *pp = p;
+  return rm;
+}
+
+/** Return total size of a list, including size of all nodes */
+static size_t list_xtra_all(xtra_f *xtra, void const *v)
+{
+  size_t rv = 0;
+  sdp_list_t const *l;
+
+  for (l = v; l; l = l->l_next) {
+    rv += STRUCT_ALIGN(rv);
+    rv += xtra(l);
+  }
+
+  return rv;
+}
+
+static
+void *list_dup_all(dup_f *dup, char **pp, void const *vsrc)
+{
+  char *p;
+  sdp_list_t const *src;
+  sdp_list_t *retval = NULL, *l, **ll = &retval;
+
+  p = *pp;
+
+  for (src = vsrc; src; src = src->l_next) {
+    p += STRUCT_ALIGN(p);
+    l = dup(&p, src);
+    assert(l);
+    *ll = l; ll = &l->l_next;
+  }
+
+  *pp = p;
+
+  return retval;
+}
+
+#if 0
+static size_t XXX_xtra(sdp_XXX_t const *YYY)
+{
+  size_t rv = sizeof(*YYY);
+  rv += strlen(YYY->YYY_encoding) + 1;
+  if (YYY->YYY_params);
+    rv += strlen(YYY->YYY_params) + 1;
+  return rv;
+}
+
+static
+sdp_XXX_t *XXX_dup(char **pp, sdp_XXX_t const *src)
+{
+  char *p;
+  sdp_XXX_t *YYY;
+
+  p = *pp; ASSERT_STRUCT_ALIGN(p);
+  YYY = memcpy(p, src, src->YYY_size);
+  p += src->YYY_size;
+  YYY->YYY_next = NULL;
+  ZZZ
+  *pp = p;
+  return YYY;
+}
+
+#endif
+
+static size_t session_xtra(sdp_session_t const *sdp)
+{
+  size_t rv = sizeof(*sdp);
+
+  PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+  STR_XTRA(rv, sdp->sdp_subject);
+  STR_XTRA(rv, sdp->sdp_information);
+  STR_XTRA(rv, sdp->sdp_uri);
+  LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+  LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+  LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+  LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+  LST_XTRA(rv, sdp->sdp_time, time_xtra);
+  PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+  LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+  STR_XTRA(rv, sdp->sdp_charset);
+  MED_XTRA_ALL(rv, sdp->sdp_media);
+
+  return rv;
+}
+
+static
+sdp_session_t *session_dup(char **pp, sdp_session_t const *src)
+{
+  char *p;
+  sdp_session_t *sdp;
+
+  p = *pp; 
+  STRUCT_DUP(p, sdp, src);
+  sdp->sdp_next = NULL;
+
+  PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+  STR_DUP(p, sdp, src, sdp_subject);
+  STR_DUP(p, sdp, src, sdp_information);
+  STR_DUP(p, sdp, src, sdp_uri);
+  LST_DUP(p, sdp, src, sdp_emails, list_dup);
+  LST_DUP(p, sdp, src, sdp_phones, list_dup);
+  LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+  LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+  LST_DUP(p, sdp, src, sdp_time, time_dup);
+  PTR_DUP(p, sdp, src, sdp_key, key_dup);
+  LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+  STR_DUP(p, sdp, src, sdp_charset);
+  MED_DUP_ALL(p, sdp, src, sdp_media);
+
+  assert((size_t)(p - *pp) == session_xtra(src));
+  *pp = p;
+  return sdp;
+}
+
+/**Duplicate an SDP session description.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP
+ * session description @a sdp allocating memory using memory @a home.
+ *
+ * @param h   Memory home
+ * @param sdp SDP session description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup(su_home_t *h, sdp_session_t const *sdp)
+{ 
+  SDP_DUP(session, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static size_t session_without_media_xtra(sdp_session_t const *sdp)
+{
+  size_t rv = sizeof(*sdp);
+
+  PTR_XTRA(rv, sdp->sdp_origin, origin_xtra);
+  STR_XTRA(rv, sdp->sdp_subject);
+  STR_XTRA(rv, sdp->sdp_information);
+  STR_XTRA(rv, sdp->sdp_uri);
+  LST_XTRA(rv, sdp->sdp_emails, list_xtra);
+  LST_XTRA(rv, sdp->sdp_phones, list_xtra);
+  LST_XTRA(rv, sdp->sdp_connection, connection_xtra);
+  LST_XTRA(rv, sdp->sdp_bandwidths, bandwidth_xtra);
+  LST_XTRA(rv, sdp->sdp_time, time_xtra);
+  PTR_XTRA(rv, sdp->sdp_key, key_xtra);
+  LST_XTRA(rv, sdp->sdp_attributes, attribute_xtra);
+  STR_XTRA(rv, sdp->sdp_charset);
+
+  return rv;
+}
+
+static
+sdp_session_t *session_without_media_dup(char **pp, sdp_session_t const *src)
+{
+  char *p;
+  sdp_session_t *sdp;
+
+  p = *pp; 
+  STRUCT_DUP(p, sdp, src);
+  sdp->sdp_next = NULL;
+
+  PTR_DUP(p, sdp, src, sdp_origin, origin_dup);
+  STR_DUP(p, sdp, src, sdp_subject);
+  STR_DUP(p, sdp, src, sdp_information);
+  STR_DUP(p, sdp, src, sdp_uri);
+  LST_DUP(p, sdp, src, sdp_emails, list_dup);
+  LST_DUP(p, sdp, src, sdp_phones, list_dup);
+  LST_DUP(p, sdp, src, sdp_connection, connection_dup);
+  LST_DUP(p, sdp, src, sdp_bandwidths, bandwidth_dup);
+  LST_DUP(p, sdp, src, sdp_time, time_dup);
+  PTR_DUP(p, sdp, src, sdp_key, key_dup);
+  LST_DUP(p, sdp, src, sdp_attributes, attribute_dup);
+  STR_DUP(p, sdp, src, sdp_charset);
+
+  sdp->sdp_media = NULL;
+  
+  assert((size_t)(p - *pp) == session_without_media_xtra(src));
+  *pp = p;
+  return sdp;
+}
+
+/* SDP_DUP macro requires this */
+typedef sdp_session_t sdp_session_without_media_t;
+
+/**Duplicate an SDP session description without media descriptions.
+ *
+ * The function sdp_session_dup() duplicates (deeply copies) an SDP session
+ * description @a sdp allocating memory using memory @a home. It does not
+ * copy the media descriptions, however.
+ *
+ * @param h     memory h
+ * @param sdp   SDP session description to be duplicated
+ *
+ * @return 
+ * If successful, a pointer to newly allocated sdp_session_t structure is
+ * returned, otherwise NULL is returned.
+ */
+
+sdp_session_t *sdp_session_dup_without_media(su_home_t *h, 
+					     sdp_session_t const *sdp)
+{ 
+  SDP_DUP(session_without_media, sdp);
+}
+
+/* ---------------------------------------------------------------------- */
+/* SDP Tag classes */
+
+#include <sofia-sip/su_tag_class.h>
+
+size_t sdptag_session_xtra(tagi_t const *t, size_t offset)
+{
+  sdp_session_t const *sdp = (sdp_session_t *)t->t_value;
+
+  if (sdp) 
+    return STRUCT_ALIGN(offset) + session_xtra(sdp);
+  else
+    return 0;
+}
+
+tagi_t *sdptag_session_dup(tagi_t *dst, tagi_t const *src, void **bb)
+{
+  sdp_session_t *sdp;
+  sdp_session_t const *srcsdp;
+  char *b;
+
+  assert(src); assert(*bb); 
+
+  b = *bb;
+  b += STRUCT_ALIGN(b);
+  srcsdp = (sdp_session_t *)src->t_value;
+
+  sdp = srcsdp ? session_dup(&b, srcsdp) : NULL;
+
+  dst->t_tag = src->t_tag;
+  dst->t_value = (tag_value_t)sdp;
+
+  *bb = b;
+
+  return dst + 1;
+}
+
+int sdptag_session_snprintf(tagi_t const *t, char b[], size_t size)
+{
+  sdp_session_t const *sdp;
+  sdp_printer_t *print;
+  size_t retval;
+
+  assert(t);
+
+  if (!t || !t->t_value) { 
+    if (size && b) b[0] = 0; 
+    return 0; 
+  }
+
+  sdp = (sdp_session_t const *)t->t_value;
+
+  print = sdp_print(NULL, sdp, b, size, 0);
+
+  retval = sdp_message_size(print);
+  
+  sdp_printer_free(print);
+
+  return (int)retval;
+}
+
+/** Tag class for SDP tags. @HIDE */
+tag_class_t sdptag_session_class[1] = 
+  {{
+    sizeof(sdptag_session_class),
+    /* tc_next */     NULL,
+    /* tc_len */      NULL,
+    /* tc_move */     NULL,
+    /* tc_xtra */     sdptag_session_xtra,
+    /* tc_dup */      sdptag_session_dup,
+    /* tc_free */     NULL,
+    /* tc_find */     NULL,
+    /* tc_snprintf */ sdptag_session_snprintf,
+    /* tc_filter */   NULL /* msgtag_str_filter */,
+    /* tc_ref_set */  t_ptr_ref_set,
+  }};
+
+
+/* ---------------------------------------------------------------------- */
+
+/* Compare two string pointers */
+su_inline 
+int str0cmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcmp(a, b);
+}
+
+/* Compare two string pointers ignoring case. */
+su_inline 
+int str0casecmp(char const *a, char const *b)
+{
+  if (a == NULL) a = "";
+  if (b == NULL) b = "";
+  return strcasecmp(a, b);
+}
+
+/** Compare two session descriptions 
+ */
+int sdp_session_cmp(sdp_session_t const *a, sdp_session_t const *b)
+{
+  int rv; 
+  sdp_bandwidth_t const *ab, *bb;
+  sdp_attribute_t const *aa, *ba;
+  sdp_media_t const *am, *bm;
+ 
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+  if (a == b)
+    return 0;
+  if ((rv = (a->sdp_version[0] - b->sdp_version[0])))
+    return rv;
+  if ((rv = sdp_origin_cmp(a->sdp_origin, b->sdp_origin)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_subject, b->sdp_subject)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_information, b->sdp_information)))
+    return rv;
+  if ((rv = str0cmp(a->sdp_uri, b->sdp_uri)))
+    return rv;
+  if ((rv = sdp_list_cmp(a->sdp_emails, b->sdp_emails)))
+    return rv;
+  if ((rv = sdp_list_cmp(a->sdp_phones, b->sdp_phones)))
+    return rv;
+  if ((rv = sdp_connection_cmp(a->sdp_connection, b->sdp_connection)))
+    return rv;
+
+  for (ab = a->sdp_bandwidths, bb = b->sdp_bandwidths; 
+       ab || bb; 
+       ab = ab->b_next, bb = bb->b_next)
+    if ((rv = sdp_bandwidth_cmp(a->sdp_bandwidths, b->sdp_bandwidths)))
+      return rv;
+
+  if ((rv = sdp_time_cmp(a->sdp_time, b->sdp_time)))
+    return rv;
+  if ((rv = sdp_key_cmp(a->sdp_key, b->sdp_key)))
+    return rv;
+
+  for (aa = a->sdp_attributes, ba = b->sdp_attributes; 
+       aa || bb; 
+       aa = aa->a_next, ba = ba->a_next)
+    if ((rv = sdp_attribute_cmp(aa, ba)))
+      return rv;
+
+  for (am = a->sdp_media, bm = b->sdp_media; 
+       am || bm; 
+       am = am->m_next, bm = bm->m_next)
+    if ((rv = sdp_media_cmp(am, bm)))
+      return rv;
+
+  return 0;
+}
+
+/** Compare two origin fields 
+ */
+int sdp_origin_cmp(sdp_origin_t const *a, sdp_origin_t const *b)
+{
+  int rv;
+
+  if ((rv = (a != NULL) - (b != NULL))) 
+    return rv;
+  if (a == b)
+    return 0;
+  if (a->o_version != b->o_version)
+    return a->o_version < b->o_version ? -1 : 1;
+  if (a->o_id != b->o_id)
+    return a->o_id < b->o_id ? -1 : 1;
+  if ((rv = strcasecmp(a->o_username, b->o_username)))
+    return rv;
+  if ((rv = strcasecmp(a->o_address->c_address, b->o_address->c_address)))
+    return rv;
+
+  return 0;
+}
+
+/** Compare two connection fields 
+ */
+int sdp_connection_cmp(sdp_connection_t const *a, sdp_connection_t const *b)
+{
+  if (a == b)
+    return 0;
+  if ((a != NULL) != (b != NULL))
+    return (a != NULL) < (b != NULL) ? -1 : 1;
+
+  if (a->c_nettype != b->c_nettype)
+    return a->c_nettype < b->c_nettype ? -1 : 1;
+  if (a->c_addrtype != b->c_addrtype)
+    return a->c_addrtype < b->c_addrtype ? -1 : 1;
+  if (a->c_ttl != b->c_ttl)
+    return a->c_ttl < b->c_ttl ? -1 : 1;
+  if (a->c_groups != b->c_groups)
+    return a->c_groups < b->c_groups ? -1 : 1;
+
+  return strcmp(a->c_address, b->c_address);
+}
+
+/** Compare two bandwidth (b=) fields */
+int sdp_bandwidth_cmp(sdp_bandwidth_t const *a, sdp_bandwidth_t const *b)
+{
+  int rv;
+
+  if (a == b)

[... 10153 lines stripped ...]



More information about the svn-commits mailing list