add sofia-sip 1.12.4 (plus some patches through 12/21/2006) to in tree libs

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3774 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris committed 2006-12-21 06:30:28 +00:00
1 parent 0cdfa4fe13
commit 2ecac238f3
719 files changed
+311340 -2

No files matched your search

@@ -0,0 +1,53 @@
2006-01-17 Martti Mela <martti.mela@nokia.com>
* msg_mime.c: defines for Mac OS X (which are lacking EBADMSG).
2005-11-08 Pekka Pessi <Pekka.Pessi@nokia.com>
* Renamed msg_test.c as test_msg.c.
* Renamed msg_test_class.[hc] as test_class.[hc],
msg_test_protos.h(.in) as test_protos.h(.in),
msg_test_table.c(.in) as test_table.c(.in).
2005-10-12 Pekka Pessi <Pekka.Pessi@nokia.com>
* Fixed msg_home() macro.
M ./libsofia-sip-ua/msg/msg.h -1 +1
2005-10-10 Pekka Pessi <Pekka.Pessi@nokia.com>
* Dox fix to msg_header_replace().
M ./libsofia-sip-ua/msg/msg_parser.c -2 +3
2005-08-15 Kai Vehmanen <kai.vehmanen@nokia.com>
* Makefile.am: Do not include msg_test_class.o in libmsg.
2005-08-01 Pekka Pessi <Pekka.Pessi@nokia.com>
* msg_mime.c: Returning -2 from msg_accept_any_d() if the list is
empty.
* msg_internal.h, msg_mclass.h, msg_mclass.c, msg_parser.awk:
Added header-specific flags in parser table for
msg_extract_errors().
* msg.h, msg.c: Added msg_extract_errors().
* msg_parser.c: Using header-specific flags to classify parsing
errors with msg_extract_errors().
Added support for apndlist headers.
* msg_header.h: Added support for apndlist headers.
* msg_mime.c: Various Accept* headers are now apndlist meaning
that they are printed on single line by default.
2005-07-18 Kai Vehmanen <kai.vehmanen@nokia.com>
* Initial import of the module to Sofia-SIP tree.
@@ -0,0 +1,17 @@
PROJECT_NAME = "msg"
OUTPUT_DIRECTORY = ../docs/html/msg
INPUT = msg.docs . sofia-sip
@INCLUDE = ../docs/Doxyfile.conf
@INCLUDE = ../sip/sip.doxyaliases
TAGFILES += ../docs/ipt.doxytags=../ipt \
../docs/su.doxytags=../su \
../docs/sip.doxytags=../sip \
../docs/nta.doxytags=../nta \
../docs/http.doxytags=../http
GENERATE_TAGFILE = ../docs/msg.doxytags
IMAGE_PATH += ../sip/images
@@ -0,0 +1,117 @@
#
# Makefile.am for msg module
#
# Copyright (C) 2005,2006 Nokia Corporation
# Contact: Pekka Pessi <pekka.pessi@nokia.com>
# Licensed under LGPL. See file COPYING.
# ----------------------------------------------------------------------
# Header paths
INCLUDES = -I$(srcdir)/../url -I../url \
-I$(srcdir)/../bnf -I../bnf \
-I$(srcdir)/../su -I../su
# ----------------------------------------------------------------------
# Build targets
noinst_LTLIBRARIES = libmsg.la
noinst_LIBRARIES = libtest_msg.a
check_PROGRAMS = msg_name_hash test_msg
# ----------------------------------------------------------------------
# Rules for building the targets
GENERATED_H = sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h
PUBLIC_H = sofia-sip/msg.h sofia-sip/msg_header.h \
sofia-sip/msg_types.h sofia-sip/msg_mclass.h \
sofia-sip/msg_mclass_hash.h sofia-sip/msg_parser.h \
sofia-sip/msg_addr.h sofia-sip/msg_date.h \
sofia-sip/msg_buffer.h sofia-sip/msg_tag_class.h \
sofia-sip/msg_mime.h
INTERNAL_H = msg_internal.h test_class.h
nobase_include_sofia_HEADERS = \
$(GENERATED_H) $(PUBLIC_H)
BUILT_SOURCES = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
libmsg_la_SOURCES = $(INTERNAL_H) \
msg.c msg_tag.c \
msg_mime.c msg_mime_table.c \
msg_header_copy.c msg_header_make.c \
msg_parser.c msg_mclass.c msg_parser_util.c \
msg_basic.c msg_generic.c msg_date.c msg_auth.c
COVERAGE_INPUT = $(libmsg_la_SOURCES) $(include_sofia_HEADERS)
libtest_msg_a_SOURCES = test_class.c test_table.c test_protos.h
LDADD = libtest_msg.a libmsg.la \
../bnf/libbnf.la \
../url/liburl.la \
../su/libsu.la
test_msg_LDFLAGS = -static
msg_name_hash_LDFLAGS = -static
# ----------------------------------------------------------------------
# Install and distribution rules
dist_pkgdata_SCRIPTS = msg_parser.awk
EXTRA_DIST = Doxyfile msg.docs \
sofia-sip/msg_mime_protos.h.in \
sofia-sip/msg_protos.h.in \
msg_mime_table.c.in \
test_protos.h.in \
test_table.c.in
# ----------------------------------------------------------------------
# Tests
TESTS = test_msg
# ----------------------------------------------------------------------
# Sofia specific rules
include ../sofia.am
MSG_PARSER_AWK = $(srcdir)/msg_parser.awk
AWK_MSG_AWK = $(AWK) -f $(MSG_PARSER_AWK)
test_protos.h: test_protos.h.in $(MSG_PARSER_AWK)
test_table.c: test_table.c.in $(MSG_PARSER_AWK)
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime_protos.h.in
sofia-sip/msg_protos.h: sofia-sip/msg_protos.h.in
msg_mime_table.c: msg_mime_table.c.in $(MSG_PARSER_AWK)
sofia-sip/msg_mime_protos.h sofia-sip/msg_protos.h: $(MSG_PARSER_AWK)
test_protos.h: test_class.h
$(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/test_protos.h.in $<
test_table.c: test_class.h
$(AWK_MSG_AWK) module=msg_test prefix=msg \
MC_HASH_SIZE=127 multipart=msg_multipart \
PT=$@ TEMPLATE=$(srcdir)/test_table.c.in $<
sofia-sip/msg_protos.h: sofia-sip/msg_mime.h
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_MIDDLE=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_protos.h.in $<
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime.h
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_mime_protos.h.in $<
msg_mime_table.c: sofia-sip/msg_mime.h
$(AWK_MSG_AWK) module=msg_multipart \
tprefix=msg prefix=mp MC_HASH_SIZE=127 \
PT=$@ TEMPLATE=$(srcdir)/msg_mime_table.c.in $<
@@ -0,0 +1,830 @@
# Makefile.in generated by automake 1.9.2 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
#
# Makefile.am for msg module
#
# Copyright (C) 2005,2006 Nokia Corporation
# Contact: Pekka Pessi <pekka.pessi@nokia.com>
# Licensed under LGPL. See file COPYING.
# ----------------------------------------------------------------------
# Header paths
# common Makefile targets for libsofia-sip-ua modules
# ---------------------------------------------------
SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) msg_name_hash.c test_msg.c
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ../..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
check_PROGRAMS = msg_name_hash$(EXEEXT) test_msg$(EXEEXT)
DIST_COMMON = $(dist_pkgdata_SCRIPTS) $(nobase_include_sofia_HEADERS) \
$(srcdir)/../sofia.am $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in ChangeLog
subdir = libsofia-sip-ua/msg
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/sac-general.m4 \
$(top_srcdir)/m4/sac-openssl.m4 $(top_srcdir)/m4/sac-su.m4 \
$(top_srcdir)/m4/sac-su2.m4 $(top_srcdir)/m4/sac-tport.m4 \
$(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h \
$(top_builddir)/libsofia-sip-ua/su/sofia-sip/su_configure.h
CONFIG_CLEAN_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = cru
libtest_msg_a_AR = $(AR) $(ARFLAGS)
libtest_msg_a_LIBADD =
am_libtest_msg_a_OBJECTS = test_class.$(OBJEXT) test_table.$(OBJEXT)
libtest_msg_a_OBJECTS = $(am_libtest_msg_a_OBJECTS)
LTLIBRARIES = $(noinst_LTLIBRARIES)
libmsg_la_LIBADD =
am__objects_1 =
am_libmsg_la_OBJECTS = $(am__objects_1) msg.lo msg_tag.lo msg_mime.lo \
msg_mime_table.lo msg_header_copy.lo msg_header_make.lo \
msg_parser.lo msg_mclass.lo msg_parser_util.lo msg_basic.lo \
msg_generic.lo msg_date.lo msg_auth.lo
libmsg_la_OBJECTS = $(am_libmsg_la_OBJECTS)
msg_name_hash_SOURCES = msg_name_hash.c
msg_name_hash_OBJECTS = msg_name_hash.$(OBJEXT)
msg_name_hash_LDADD = $(LDADD)
msg_name_hash_DEPENDENCIES = libtest_msg.a libmsg.la ../bnf/libbnf.la \
../url/liburl.la ../su/libsu.la
test_msg_SOURCES = test_msg.c
test_msg_OBJECTS = test_msg.$(OBJEXT)
test_msg_LDADD = $(LDADD)
test_msg_DEPENDENCIES = libtest_msg.a libmsg.la ../bnf/libbnf.la \
../url/liburl.la ../su/libsu.la
am__installdirs = "$(DESTDIR)$(pkgdatadir)" \
"$(DESTDIR)$(include_sofiadir)"
dist_pkgdataSCRIPT_INSTALL = $(INSTALL_SCRIPT)
SCRIPTS = $(dist_pkgdata_SCRIPTS)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) -I$(top_builddir)/libsofia-sip-ua/su/sofia-sip
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile --tag=CC $(CC) $(DEFS) \
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
$(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link --tag=CC $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) \
msg_name_hash.c test_msg.c
DIST_SOURCES = $(libtest_msg_a_SOURCES) $(libmsg_la_SOURCES) \
msg_name_hash.c test_msg.c
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
nobase_include_sofiaHEADERS_INSTALL = $(install_sh_DATA)
HEADERS = $(nobase_include_sofia_HEADERS)
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
COREFOUNDATION_FALSE = @COREFOUNDATION_FALSE@
COREFOUNDATION_TRUE = @COREFOUNDATION_TRUE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CWFLAG = @CWFLAG@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DOXYGEN = @DOXYGEN@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_COVERAGE_FALSE = @ENABLE_COVERAGE_FALSE@
ENABLE_COVERAGE_TRUE = @ENABLE_COVERAGE_TRUE@
ETAGS = @ETAGS@
EXEEXT = @EXEEXT@
EXPENSIVE_CHECKS_FALSE = @EXPENSIVE_CHECKS_FALSE@
EXPENSIVE_CHECKS_TRUE = @EXPENSIVE_CHECKS_TRUE@
F77 = @F77@
FFLAGS = @FFLAGS@
GLIB_CFLAGS = @GLIB_CFLAGS@
GLIB_LIBS = @GLIB_LIBS@
GLIB_VERSION = @GLIB_VERSION@
HAVE_DOXYGEN_FALSE = @HAVE_DOXYGEN_FALSE@
HAVE_DOXYGEN_TRUE = @HAVE_DOXYGEN_TRUE@
HAVE_GLIB_FALSE = @HAVE_GLIB_FALSE@
HAVE_GLIB_TRUE = @HAVE_GLIB_TRUE@
HAVE_MINGW32_FALSE = @HAVE_MINGW32_FALSE@
HAVE_MINGW32_TRUE = @HAVE_MINGW32_TRUE@
HAVE_NTLM_FALSE = @HAVE_NTLM_FALSE@
HAVE_NTLM_TRUE = @HAVE_NTLM_TRUE@
HAVE_TLS_FALSE = @HAVE_TLS_FALSE@
HAVE_TLS_TRUE = @HAVE_TLS_TRUE@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBVER_SOFIA_SIP_UA_AGE = @LIBVER_SOFIA_SIP_UA_AGE@
LIBVER_SOFIA_SIP_UA_CUR = @LIBVER_SOFIA_SIP_UA_CUR@
LIBVER_SOFIA_SIP_UA_GLIB_AGE = @LIBVER_SOFIA_SIP_UA_GLIB_AGE@
LIBVER_SOFIA_SIP_UA_GLIB_CUR = @LIBVER_SOFIA_SIP_UA_GLIB_CUR@
LIBVER_SOFIA_SIP_UA_GLIB_REV = @LIBVER_SOFIA_SIP_UA_GLIB_REV@
LIBVER_SOFIA_SIP_UA_GLIB_SOVER = @LIBVER_SOFIA_SIP_UA_GLIB_SOVER@
LIBVER_SOFIA_SIP_UA_REV = @LIBVER_SOFIA_SIP_UA_REV@
LIBVER_SOFIA_SIP_UA_SOVER = @LIBVER_SOFIA_SIP_UA_SOVER@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
MINGW_ENVIRONMENT = @MINGW_ENVIRONMENT@
MOSTLYCLEANFILES = @MOSTLYCLEANFILES@
NDEBUG_FALSE = @NDEBUG_FALSE@
NDEBUG_TRUE = @NDEBUG_TRUE@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
REPLACE_LIBADD = @REPLACE_LIBADD@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOFIA_CFLAGS = @SOFIA_CFLAGS@
SOFIA_GLIB_PKG_REQUIRES = @SOFIA_GLIB_PKG_REQUIRES@
STRIP = @STRIP@
TESTS_ENVIRONMENT = @TESTS_ENVIRONMENT@
VERSION = @VERSION@
VER_LIBSOFIA_SIP_UA_MAJOR_MINOR = @VER_LIBSOFIA_SIP_UA_MAJOR_MINOR@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_F77 = @ac_ct_F77@
ac_ct_LD = @ac_ct_LD@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
include_sofiadir = @include_sofiadir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
INCLUDES = -I$(srcdir)/../url -I../url \
-I$(srcdir)/../bnf -I../bnf \
-I$(srcdir)/../su -I../su
# ----------------------------------------------------------------------
# Build targets
noinst_LTLIBRARIES = libmsg.la
noinst_LIBRARIES = libtest_msg.a
# ----------------------------------------------------------------------
# Rules for building the targets
GENERATED_H = sofia-sip/msg_protos.h sofia-sip/msg_mime_protos.h
PUBLIC_H = sofia-sip/msg.h sofia-sip/msg_header.h \
sofia-sip/msg_types.h sofia-sip/msg_mclass.h \
sofia-sip/msg_mclass_hash.h sofia-sip/msg_parser.h \
sofia-sip/msg_addr.h sofia-sip/msg_date.h \
sofia-sip/msg_buffer.h sofia-sip/msg_tag_class.h \
sofia-sip/msg_mime.h
INTERNAL_H = msg_internal.h test_class.h
nobase_include_sofia_HEADERS = \
$(GENERATED_H) $(PUBLIC_H)
BUILT_SOURCES = $(GENERATED_H) msg_mime_table.c test_table.c test_protos.h
libmsg_la_SOURCES = $(INTERNAL_H) \
msg.c msg_tag.c \
msg_mime.c msg_mime_table.c \
msg_header_copy.c msg_header_make.c \
msg_parser.c msg_mclass.c msg_parser_util.c \
msg_basic.c msg_generic.c msg_date.c msg_auth.c
COVERAGE_INPUT = $(libmsg_la_SOURCES) $(include_sofia_HEADERS)
libtest_msg_a_SOURCES = test_class.c test_table.c test_protos.h
LDADD = libtest_msg.a libmsg.la \
../bnf/libbnf.la \
../url/liburl.la \
../su/libsu.la
test_msg_LDFLAGS = -static
msg_name_hash_LDFLAGS = -static
# ----------------------------------------------------------------------
# Install and distribution rules
dist_pkgdata_SCRIPTS = msg_parser.awk
EXTRA_DIST = Doxyfile msg.docs \
sofia-sip/msg_mime_protos.h.in \
sofia-sip/msg_protos.h.in \
msg_mime_table.c.in \
test_protos.h.in \
test_table.c.in
# ----------------------------------------------------------------------
# Tests
TESTS = test_msg
AM_CFLAGS = $(CWFLAG) $(SOFIA_CFLAGS)
DISTCLEANFILES = $(BUILT_SOURCES)
# rules for building tag files
TAG_AWK = $(top_srcdir)/libsofia-sip-ua/su/tag_dll.awk
INTERNAL_INCLUDES = \
-I$(srcdir)/../features -I../features \
-I$(srcdir)/../ipt -I../ipt \
-I$(srcdir)/../iptsec -I../iptsec \
-I$(srcdir)/../bnf -I../bnf \
-I$(srcdir)/../http -I../http \
-I$(srcdir)/../msg -I../msg \
-I$(srcdir)/../nth -I../nth \
-I$(srcdir)/../nta -I../nta \
-I$(srcdir)/../nea -I../nea \
-I$(srcdir)/../nua -I../nua \
-I$(srcdir)/../soa -I../soa \
-I$(srcdir)/../sdp -I../sdp \
-I$(srcdir)/../sip -I../sip \
-I$(srcdir)/../soa -I../soa \
-I$(srcdir)/../sresolv -I../sresolv \
-I$(srcdir)/../tport -I../tport \
-I$(srcdir)/../stun -I../stun \
-I$(srcdir)/../url -I../url \
-I$(srcdir)/../su -I../su
# ----------------------------------------------------------------------
# Sofia specific rules
MSG_PARSER_AWK = $(srcdir)/msg_parser.awk
AWK_MSG_AWK = $(AWK) -f $(MSG_PARSER_AWK)
all: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) all-am
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/../sofia.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libsofia-sip-ua/msg/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu libsofia-sip-ua/msg/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
libtest_msg.a: $(libtest_msg_a_OBJECTS) $(libtest_msg_a_DEPENDENCIES)
-rm -f libtest_msg.a
$(libtest_msg_a_AR) libtest_msg.a $(libtest_msg_a_OBJECTS) $(libtest_msg_a_LIBADD)
$(RANLIB) libtest_msg.a
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
test "$$dir" != "$$p" || dir=.; \
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
libmsg.la: $(libmsg_la_OBJECTS) $(libmsg_la_DEPENDENCIES)
$(LINK) $(libmsg_la_LDFLAGS) $(libmsg_la_OBJECTS) $(libmsg_la_LIBADD) $(LIBS)
clean-checkPROGRAMS:
@list='$(check_PROGRAMS)'; for p in $$list; do \
f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
done
msg_name_hash$(EXEEXT): $(msg_name_hash_OBJECTS) $(msg_name_hash_DEPENDENCIES)
@rm -f msg_name_hash$(EXEEXT)
$(LINK) $(msg_name_hash_LDFLAGS) $(msg_name_hash_OBJECTS) $(msg_name_hash_LDADD) $(LIBS)
test_msg$(EXEEXT): $(test_msg_OBJECTS) $(test_msg_DEPENDENCIES)
@rm -f test_msg$(EXEEXT)
$(LINK) $(test_msg_LDFLAGS) $(test_msg_OBJECTS) $(test_msg_LDADD) $(LIBS)
install-dist_pkgdataSCRIPTS: $(dist_pkgdata_SCRIPTS)
@$(NORMAL_INSTALL)
test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)"
@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f $$d$$p; then \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " $(dist_pkgdataSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \
$(dist_pkgdataSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \
else :; fi; \
done
uninstall-dist_pkgdataSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(dist_pkgdata_SCRIPTS)'; for p in $$list; do \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \
rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \
done
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_auth.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_basic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_date.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_generic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_header_copy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_header_make.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_mclass.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_mime.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_mime_table.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_name_hash.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_parser.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_parser_util.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg_tag.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_class.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_msg.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_table.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c $<
.c.obj:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
.c.lo:
@am__fastdepCC_TRUE@ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
install-nobase_include_sofiaHEADERS: $(nobase_include_sofia_HEADERS)
@$(NORMAL_INSTALL)
test -z "$(include_sofiadir)" || $(mkdir_p) "$(DESTDIR)$(include_sofiadir)"
@$(am__vpath_adj_setup) \
list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
$(am__vpath_adj) \
echo " $(nobase_include_sofiaHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(include_sofiadir)/$$f'"; \
$(nobase_include_sofiaHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(include_sofiadir)/$$f"; \
done
uninstall-nobase_include_sofiaHEADERS:
@$(NORMAL_UNINSTALL)
@$(am__vpath_adj_setup) \
list='$(nobase_include_sofia_HEADERS)'; for p in $$list; do \
$(am__vpath_adj) \
echo " rm -f '$(DESTDIR)$(include_sofiadir)/$$f'"; \
rm -f "$(DESTDIR)$(include_sofiadir)/$$f"; \
done
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
check-TESTS: $(TESTS)
@failed=0; all=0; xfail=0; xpass=0; skip=0; \
srcdir=$(srcdir); export srcdir; \
list='$(TESTS)'; \
if test -n "$$list"; then \
for tst in $$list; do \
if test -f ./$$tst; then dir=./; \
elif test -f $$tst; then dir=; \
else dir="$(srcdir)/"; fi; \
if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
all=`expr $$all + 1`; \
case " $(XFAIL_TESTS) " in \
*" $$tst "*) \
xpass=`expr $$xpass + 1`; \
failed=`expr $$failed + 1`; \
echo "XPASS: $$tst"; \
;; \
*) \
echo "PASS: $$tst"; \
;; \
esac; \
elif test $$? -ne 77; then \
all=`expr $$all + 1`; \
case " $(XFAIL_TESTS) " in \
*" $$tst "*) \
xfail=`expr $$xfail + 1`; \
echo "XFAIL: $$tst"; \
;; \
*) \
failed=`expr $$failed + 1`; \
echo "FAIL: $$tst"; \
;; \
esac; \
else \
skip=`expr $$skip + 1`; \
echo "SKIP: $$tst"; \
fi; \
done; \
if test "$$failed" -eq 0; then \
if test "$$xfail" -eq 0; then \
banner="All $$all tests passed"; \
else \
banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
fi; \
else \
if test "$$xpass" -eq 0; then \
banner="$$failed of $$all tests failed"; \
else \
banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
fi; \
fi; \
dashes="$$banner"; \
skipped=""; \
if test "$$skip" -ne 0; then \
skipped="($$skip tests were not run)"; \
test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
dashes="$$skipped"; \
fi; \
report=""; \
if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
report="Please report to $(PACKAGE_BUGREPORT)"; \
test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
dashes="$$report"; \
fi; \
dashes=`echo "$$dashes" | sed s/./=/g`; \
echo "$$dashes"; \
echo "$$banner"; \
test -z "$$skipped" || echo "$$skipped"; \
test -z "$$report" || echo "$$report"; \
echo "$$dashes"; \
test "$$failed" -eq 0; \
else :; fi
distdir: $(DISTFILES)
$(mkdir_p) $(distdir)/.. $(distdir)/sofia-sip
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkdir_p) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) check-am
all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(SCRIPTS) $(HEADERS)
installdirs:
for dir in "$(DESTDIR)$(pkgdatadir)" "$(DESTDIR)$(include_sofiadir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: $(BUILT_SOURCES)
$(MAKE) $(AM_MAKEFLAGS) install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
clean: clean-am
clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
clean-noinstLIBRARIES clean-noinstLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-libtool distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
install-data-am: install-dist_pkgdataSCRIPTS \
install-nobase_include_sofiaHEADERS
install-exec-am:
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-dist_pkgdataSCRIPTS uninstall-info-am \
uninstall-nobase_include_sofiaHEADERS
.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
clean-checkPROGRAMS clean-generic clean-libtool \
clean-noinstLIBRARIES clean-noinstLTLIBRARIES ctags distclean \
distclean-compile distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am html html-am info info-am \
install install-am install-data install-data-am \
install-dist_pkgdataSCRIPTS install-exec install-exec-am \
install-info install-info-am install-man \
install-nobase_include_sofiaHEADERS install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-dist_pkgdataSCRIPTS \
uninstall-info-am uninstall-nobase_include_sofiaHEADERS
built-sources: $(BUILT_SOURCES)
clean-built-sources:
-rm -rf $(BUILT_SOURCES) $(BUILT_SOURCES:%=$(srcdir)/%)
*_tag_ref.c: $(TAG_AWK)
%_tag_ref.c: %_tag.c
$(AWK) -f $(TAG_AWK) NODLL=1 $(TAG_DLL_FLAGS) $<
@ENABLE_COVERAGE_TRUE@coverage:
@ENABLE_COVERAGE_TRUE@ @$(top_srcdir)/scripts/coverage $(COVERAGE_FLAGS) $(COVERAGE_INPUT)
../bnf/libbnf.la ../http/libhttp.la ../ipt/libipt.la ../iptsec/libiptsec.la \
../msg/libmsg.la ../nea/libnea.la ../nta/libnta.la ../nth/libnth.la \
../nua/libnua.la ../sdp/libsdp.la ../sip/libsip.la ../soa/libsoa.la \
../sresolv/libsresolv.la ../stun/libstun.la ../su/libsu.la \
../tport/libtport.la ../url/liburl.la:
$(MAKE) -C $(@D) $(@F)
test_protos.h: test_protos.h.in $(MSG_PARSER_AWK)
test_table.c: test_table.c.in $(MSG_PARSER_AWK)
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime_protos.h.in
sofia-sip/msg_protos.h: sofia-sip/msg_protos.h.in
msg_mime_table.c: msg_mime_table.c.in $(MSG_PARSER_AWK)
sofia-sip/msg_mime_protos.h sofia-sip/msg_protos.h: $(MSG_PARSER_AWK)
test_protos.h: test_class.h
$(AWK_MSG_AWK) module=msg_test NO_MIDDLE=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/test_protos.h.in $<
test_table.c: test_class.h
$(AWK_MSG_AWK) module=msg_test prefix=msg \
MC_HASH_SIZE=127 multipart=msg_multipart \
PT=$@ TEMPLATE=$(srcdir)/test_table.c.in $<
sofia-sip/msg_protos.h: sofia-sip/msg_mime.h
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_MIDDLE=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_protos.h.in $<
sofia-sip/msg_mime_protos.h: sofia-sip/msg_mime.h
@-mkdir sofia-sip 2>/dev/null || true
$(AWK_MSG_AWK) module=msg NO_FIRST=1 NO_LAST=1 \
PR=$@ TEMPLATE=$(srcdir)/sofia-sip/msg_mime_protos.h.in $<
msg_mime_table.c: sofia-sip/msg_mime.h
$(AWK_MSG_AWK) module=msg_multipart \
tprefix=msg prefix=mp MC_HASH_SIZE=127 \
PT=$@ TEMPLATE=$(srcdir)/msg_mime_table.c.in $<
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
+409
View File
@@ -0,0 +1,409 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@file msg.c Message object implementation.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jun 8 19:28:55 2000 ppessi
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include <sofia-sip/su_alloc.h> /* XXX */
#include <sofia-sip/su.h>
#include "msg_internal.h"
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_mclass.h"
/**
* Create a message.
*
* @relatesalso msg_s
*
* @param mc message class
* @param flags message control flags
*/
msg_t *msg_create(msg_mclass_t const *mc, int flags)
{
msg_t *msg = su_home_new(sizeof(*msg) + mc->mc_msize);
if (msg) {
if ((flags & MSG_FLG_THRDSAFE) &&
su_home_threadsafe(msg->m_home) < 0) {
su_home_unref(msg->m_home);
return NULL;
}
msg->m_refs++;
msg->m_tail = &msg->m_chain;
msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
msg->m_maxsize = 0;
flags &= MSG_FLG_USERMASK;
msg->m_class = mc;
msg->m_oflags = flags;
msg->m_object = (void *)(msg + 1);
msg->m_object->msg_size = mc->mc_msize;
msg->m_object->msg_flags = mc->mc_flags | flags;
msg->m_object->msg_common->h_class = (void *)mc;
}
return msg;
}
/**Increment a message reference count.
*
* @relatesalso msg_s
*
* Creates a reference to a message. The
* referenced message is not freed until all the references have been
* destroyed.
*
* @param msg message of which a reference is created
*
* @return
* A pointer to a message.
*/
msg_t *msg_ref_create(msg_t *msg)
{
if (msg) {
su_home_mutex_lock(msg->m_home);
msg->m_refs++;
su_home_mutex_unlock(msg->m_home);
}
return msg;
}
/**Set a message parent.
*
* @relatesalso msg_s
*
* Set a parent for a message. The parent message is not destroyed until all
* its kids have been destroyed - each kid keeps a reference to its parent
* message.
*
* @param kid child message
* @param dad parent message
*/
void msg_set_parent(msg_t *kid, msg_t *dad)
{
if (kid) {
msg_t *step_dad = kid->m_parent;
if (dad && step_dad && step_dad != dad)
msg_ref_destroy(step_dad);
kid->m_parent = msg_ref_create(dad);
}
}
/** Destroy a reference to a message.
*
* @relatesalso msg_s
*
* @param ref pointer to msg object
*
* @deprecated Use msg_destroy() instead.
*/
void msg_ref_destroy(msg_t *ref)
{
msg_destroy(ref);
}
/**Deinitialize and free a message.
*
* @relatesalso msg_s
*
* @param msg message to be destroyed
*/
void msg_destroy(msg_t *msg)
{
msg_t *parent;
for (; msg; msg = parent) {
int refs;
su_home_mutex_lock(msg->m_home);
parent = msg->m_parent;
if (msg->m_refs)
msg->m_refs--;
refs = msg->m_refs;
su_home_mutex_unlock(msg->m_home);
if (refs)
break;
su_home_zap(msg->m_home);
}
}
/* Message object routines */
/**Retrieve public message structure.
*
* Get a pointer to the public message structure.
*
* @param msg pointer to msg object
*
* @returns
* A pointer to the public message structure, or NULL if none.
*/
msg_pub_t *msg_object(msg_t const *msg)
{
if (msg)
return msg->m_object;
else
return NULL;
}
/**Retrieve public message structure of given type.
*
* @relatesalso msg_s
*
* Get a pointer to the public message structure of the
* given protocol.
*
* @param msg pointer to msg object
* @param tag tag of public message structure
*
* @returns
* A pointer to the public message structure, or NULL if there is none or
* the message is not for desired protocol.
*/
msg_pub_t *msg_public(msg_t const *msg, void *tag)
{
if (msg && msg->m_class->mc_tag == tag)
return msg->m_object;
else
return NULL;
}
/**Retrieve message class.
*
* @relatesalso msg_s
*
* Get a pointer to the message class object
* (factory object for the message).
*
* @param msg pointer to msg object
*
* @returns
* A pointer to the message class, or NULL if none.
*/
msg_mclass_t const *msg_mclass(msg_t const *msg)
{
if (msg)
return msg->m_class;
else
return NULL;
}
/* Address management */
/** Zero the message address.
*
* @relatesalso msg_s
*
* Zero the address and addressinfo structures associated with the message.
*
* @sa msg_addrinfo(), msg_set_address(), msg_get_address(), msg_addr_copy().
*/
void msg_addr_zero(msg_t *msg)
{
memset(&msg->m_addr, 0, sizeof(&msg->m_addr));
memset(&msg->m_addrinfo, 0, sizeof(&msg->m_addrinfo));
msg->m_addrinfo.ai_addrlen = sizeof(msg->m_addr);
msg->m_addrinfo.ai_addr = &msg->m_addr->su_sa;
}
/** Get pointer to socket address structure.
*
* @relatesalso msg_s
*
* @deprecated Use msg_get_address() or msg_set_address() instead.
*/
su_sockaddr_t *msg_addr(msg_t *msg)
{
return msg ? msg->m_addr : 0;
}
/** Get message address.
*
* @relatesalso msg_s
*
* Copy the socket address associated with the message to the supplied
* socket address struture.
*
* @param msg pointer to msg object
* @param su pointer to socket address structure
* @param return_len return parameter value for length
* of socket address structure
*
* @sa msg_addrinfo(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
*/
int msg_get_address(msg_t *msg, su_sockaddr_t *su, socklen_t *return_len)
{
if (msg && return_len && *return_len >= msg->m_addrinfo.ai_addrlen) {
*return_len = (socklen_t)msg->m_addrinfo.ai_addrlen;
if (su)
memcpy(su, msg->m_addr, msg->m_addrinfo.ai_addrlen);
return 0;
}
if (msg)
msg->m_errno = EFAULT;
return -1;
}
/** Set message address.
*
* @relatesalso msg_s
*
* Copy the supplied socket address to the socket address structure
* associated with the message.
*
* @param msg pointer to msg object
* @param su pointer to socket address structure
* @param sulen length of socket address structure
*
* @sa msg_addrinfo(), msg_get_address(), msg_addr_zero(), msg_addr_copy().
*/
int msg_set_address(msg_t *msg, su_sockaddr_t const *su, socklen_t sulen)
{
if (sulen < (sizeof msg->m_addr) && msg && su) {
memcpy(msg->m_addr, su, msg->m_addrinfo.ai_addrlen = sulen);
msg->m_addrinfo.ai_family = su->su_family;
return 0;
}
if (msg)
msg->m_errno = EFAULT;
return -1;
}
/** Get addrinfo structure.
*
* @relatesalso msg_s
*
* Get pointer to the addrinfo structure associated with the message.
*
* @param msg pointer to msg object
*
* @retval pointer to addrinfo structure
* @retval NULL if msg is NULL
*
* @sa msg_get_address(), msg_set_address(), msg_addr_zero(), msg_addr_copy().
*/
su_addrinfo_t *msg_addrinfo(msg_t *msg)
{
return msg ? &msg->m_addrinfo : 0;
}
/**Copy message address.
*
* @relatesalso msg_s
*
* Copy the addrinfo and socket address structures from @a src to the @a dst
* message object.
*
* @param dst pointer to destination message object
* @param src pointer to source message object
*
* @sa msg_addrinfo(), msg_get_address(), msg_set_address(), msg_addr_zero().
*/
void msg_addr_copy(msg_t *dst, msg_t const *src)
{
dst->m_addrinfo = src->m_addrinfo;
dst->m_addrinfo.ai_next = NULL;
dst->m_addrinfo.ai_canonname = NULL;
memcpy(dst->m_addrinfo.ai_addr = &dst->m_addr->su_sa,
src->m_addr, src->m_addrinfo.ai_addrlen);
if (dst->m_addrinfo.ai_addrlen < sizeof(dst->m_addr))
memset((char *)dst->m_addr + dst->m_addrinfo.ai_addrlen, 0,
sizeof(dst->m_addr) - dst->m_addrinfo.ai_addrlen);
}
/** Get error classification flags.
*
* @relatesalso msg_s
*
* If the message parser fails to parse certain headers in the message, it
* sets the corresponding extract error flags. The flags corresponding to
* each header are stored in the message parser (msg_mclass_t) structure.
* They are set when the header is added to the parser table.
*
* The SIP flags are defined in <sofia-sip/sip_headers.h>. For well-known
* SIP headers, the flags for each header are listed in a separate text file
* (sip_bad_mask) read by msg_parser.awk.
*
* The flags can be used directly by NTA (the mask triggering 400 response
* is set with NTATAG_BAD_REQ_MASK(), the mask triggering response messages
* to be dropped is set with NTATAG_BAD_RESP_MASK()). Alternatively the
* application can check them based on the method or required SIP features.
*
* @sa msg_mclass_insert_with_mask(), NTATAG_BAD_REQ_MASK(),
* NTATAG_BAD_RESP_MASK().
*/
unsigned msg_extract_errors(msg_t const *msg)
{
return msg ? msg->m_extract_err : (unsigned)-1;
}
/** Get error number associated with message.
*
* @relatesalso msg_s
*
* @param msg pointer to msg object
*
*/
int msg_errno(msg_t const *msg)
{
return msg ? msg->m_errno : EINVAL;
}
/** Set error number associated with message.
*
* @relatesalso msg_s
*
* @param msg pointer to msg object
* @param err error value (as defined in <sofia-sip/su_errno.h>).
*
*/
void msg_set_errno(msg_t *msg, int err)
{
if (msg)
msg->m_errno = err;
}
+506
View File
@@ -0,0 +1,506 @@
/* -*- text -*- */
/**@MODULEPAGE "msg" - Message Parser Module
@section msg_meta Module Meta Information
This module contains parser and functions for manipulating messages and
headers for text-based protocols like SIP, HTTP or RTSP. It also
provides parsing of MIME headers and MIME multipart messages common to
these protocols.
@CONTACT Pekka Pessi <Pekka.Pessi@nokia.com>
@STATUS @SofiaSIP Core library
@LICENSE LGPL
@par Contributor(s):
- Pekka Pessi <Pekka.Pessi@nokia.com>
@section msg_contents Contents of msg Module
The msg module contains the public header files as follows:
- <sofia-sip/msg.h> base message interfaces
- <sofia-sip/msg_types.h> message and header struct definitions and typedefs
- <sofia-sip/msg_protos.h> prototypes of header-specific functions for generic headers
- <sofia-sip/msg_header.h> function prototypes and macros for manipulating message
headers
- <sofia-sip/msg_addr.h> functions for accessing network addresses and I/O vectors
associated with the message
- <sofia-sip/msg_date.h> types and functions for handling dates and times
- <sofia-sip/msg_mime.h> types, function prototypes and macros for MIME headers
and @ref msg_multipart "multipart messages"
- <sofia-sip/msg_mime_protos.h> prototypes of MIME-header-specific functions
In addition to this interface, the @ref msg_parser "parser documentation"
contains description of the functionality required when an existing parser
is extended by a new header or a parser is created for a completely new
protocol. It is possible to add new headers to the parser or extend the
definition of existing ones. The header files used for constructing these
parsers are as follows:
- <sofia-sip/msg_parser.h> parsing functions, macros
- <sofia-sip/msg_mclass.h> message factory object definition
- <sofia-sip/msg_mclass_hash.h> hashing of header names
@section msg_overview Parsers, Messages and Headers
The Sofia @b msg module contains interface to the text-based parsers for
RFC822-like message, the header and message objects. Currently, there
are three parsers defined: SIP, HTTP, and MIME.
The C structure corresponding to each header is defined either in a
<sofia-sip/msg_types.h> or in a protocol-specific header file. These
protocol-specific header files include <sofia-sip/sip.h>, <sofia-sip/http.h>, and
<sofia-sip/msg_mime.h>. For each header, there is defined a @em header @em class
structure, some standard functions, and tags for including them in tag
lists.
As a convention, all the identifiers for SIP headers start with prefix @c
sip and all the macros with @c SIP. Same thing holds for HTTP, too: it
uses prefix @c http. However, the MIME headers
and the functions related to them are defined within the @b msg module and
they use prefix @c msg. If a SIP or HTTP header uses a structure
defined in <sofia-sip/msg_types.h>, there is a typedef suitable for the particular
protocol, for example @b Accept header is defined multiple times:
@code
typedef struct msg_accept_s sip_accept_t;
typedef struct msg_accept_s http_accept_t;
@endcode
For header @e X of protocol @e NS, there are types, functions, macros and
header class as follows:
- @c ns_X_t is the structure used to store parsed header,
- @c ns_hclass_t @c ns_X_class[] contains the @em header @em class
for header X,
- @c NS_X_INIT() initializes a static instance of @c ns_X_t,
- @c ns_X_init() initializes a dynamic instance of @c ns_X_t,
- @c ns_is_X() tests if header object is instance of header X,
- @c ns_X_make() creates a header X object by decoding given string,
- @c ns_X_format() creates a header X object by decoding given
@c printf() list,
- @c ns_X_dup() duplicates (deeply copies) the header X,
- @c ns_X_copy() copies the header X,
- @c NSTAG_X() is used include instance of @c ns_X_t in a tag list, and
- @c NSTAG_X_STR() is used to include string containing value header
in a tag list.
The declarations of header tags and the prototypes for these functions can
be imported separately from the type definitions, for instance, the tags
related to SIP headers are declared in the include file
<sofia-sip/sip_tag.h>, and the header-specific functions in
<sofia-sip/sip_header.h>.
@section parser_intro Parsing Text Messages
Sofia text parser follows @em recursive-descent principle. In other words,
it is a program that descends the syntax tree top-down recursively.
(All syntax trees have root at top and they grow downwards.)
In the case of SIP, HTTP and other similar protocols, such a parser is very
efficient. The parser can choose between different forms based on each
token, as the protocol syntax is carefully designed so that it requires only
minimal scan-ahead. It is also easy to extend a recursive-descent parser via
a standard API, unlike, for instance, a LALR parser generated by @em Bison.
The abstract message module @b msg contains a high-level parser engine that
drives the parsing process and invokes the protocol-specific parser for each
header. As there is no low-layer framing between the RFC822-style messages,
the parser considers any received data, be it a UDP datagram or a TCP
stream, as a @em byte @em stream. The protocol-specific parsers controls how
a byte stream is split into separate messages or if it consists of a single
message only.
The parser engine works by separating stream into fragments, then passing
the fragment to a suitable parser. A fragment is a piece of message that is
parsed during a single step: the first line, each header, the empty line
between headers and message body, the message body. (In case of HTTP, the
message body can consists of multiple fragments known as chunks.)
The parser starts by separating the first line (e.g., request or status
line) from the byte stream, then passing the line to the suitable parser.
After first line comes the message headers. The parser continues parsing
process by extracting headers, each on their own line, from the stream and
passing contents of each header to its parser. The message structure is
populated based on the parsing results. When an empty line - indicating end
of headers - is encountered, the control is passed to the protocol-specific
parser. Protocol-specific functions take care of extracting the possible
message body from the byte stream.
After parsing process is completed, it can be given to the upper layers
(typically a protocol state machine). The parser continues processing the
stream and feeding the messages to protocol engine until the end of the
stream is reached.
@image html sip-parser.gif Separating byte stream to messages
@image latex sip-parser.eps Separating byte stream to messages
When the parsing process has completed, the first line, each header,
separator and the message body are all in their own fragment structure. The
fragments form a dual-linked list known as @e fragment @e chain as shown in
the above figure. The memory buffers for the message, the fragment chain,
and a whole lot of other stuff is held by the generic message type, #msg_t,
defined in <msg.h>. The internal structure of #msg_t is known only within @b
msg module and it is opaque to other modules.
The @b msg parser engine also drives the reverse process, invoking the
encoding method of each fragment so that the whole outgoing message can be
encoded properly.
@section msg_header_struct Message Header as a C struct
Just separating headers from each other and from the message body is not
usually enough. When a header contains structured data, the header contents
should be converted to a form that is convenient to use from C programs. For
that purpose, the message parser needs a parsing function specific to each
individual header. This parsing function divides the contents of the header
into semantically meaningful segments and stores the result in the structure
specific to each header.
The parser engine passes the fragment contents to the parsing function after
it has separated the fragment from the rest of the message. The parser
engine selects correct @e header @e class either by implication (in case of
first line), or it searches for the header class from the hash table using
the header name as the hash key. The @e header @e class contains a pointer
to the parsing function. The parser has also special header classes for
headers with errors and @e unknown headers, header with a name that is not
regocnized by the parser.
For instance, the Accept header has following syntax:
@code
Accept = "Accept" ":" #( media-range [ accept-params ] )
media-range = ( "*" "/" "*"
| ( type "/" "*" )
| ( type "/" subtype ) ) *( ";" parameter )
accept-params = ";" "q" "=" qvalue *( accept-extension )
accept-extension = ";" token [ "=" ( token | quoted-string ) ]
@endcode
When an Accept header is parsed, the header parser function (msg_accept_d())
separates the @e type, @e subtype, and each parameter in the list to
strings. The parsing result is assigned to a #msg_accept_t structure, which is
defined as follows:
@code
typedef struct msg_accept_s
{
msg_common_t ac_common[1]; //< Common fragment info
msg_accept_t *ac_next; //< Pointer to next Accept header
char const *ac_type; //< Pointer to type/subtype
char const *ac_subtype; //< Points after first slash in type
msg_param_t const *ac_params; //< List of parameters
msg_param_t ac_q; //< Value of q parameter
}
msg_accept_t;
@endcode
The string containing the @e type is put into the @c ac_type field, the @e
subtype after slash in the can be found in the @c ac_subtype field, and the
list of @e accept-params (together with media-specific-parameters) is put in
the @c ac_params array. If there is a @e q parameter present, a pointer to
the @c qvalue is assigned to @c ac_q field.
In the beginning of the header structure there are two boilerplate members.
The @c ac_common[1] contains information common to all message fragments.
The @c ac_next is a pointer to next header field with the same name, in case
a message contains multiple @b Accept headers or multiple comma-separated
header fields are located in a single line.
@section msg_object_example Representing a Message as a C struct
It is not enough to represent a message as a list of headers following each
other. The programmer also needs a convenient way to access certain headers
at the message level, for example, accessing directly the @b Accept header
instead of going through all headers and examining their name. The
structured view to the message is provided via a message-specific C struct.
In general, its type is msg_pub_t (it provides public view to message). The
protocol-specific type is #sip_t, #http_t or #msg_multipart_t for
SIP, HTTP and MIME, respectively.
So, a single message is represented by two objects, first object (#msg_t) is
private to the @b msg module and opaque by an application programmer, second
(#sip_t, #http_t or #msg_multipart_t) is a public protocol-specific
structure accessible by all.
@note The application programmer can obtain a pointer to the
protocol-specific structure from an #msg_t object using msg_public()
function. The msg_public() takes a protocol tag, a well-known identifier, as
its argument. The SIP, HTTP and MIME already define a wrapper around
msg_public(), for example, a #sip_t structure can be obtained with
sip_object() function (or macro).
As an example, the #sip_t structure is defined as follows:
@code
typedef struct sip_s {
msg_common_t sip_common[1]; // Used with recursive inclusion
msg_pub_t *sip_next; // Ditto
void *sip_user; // Application data
unsigned sip_size; // Size of the structure with
// extension headers
int sip_flags; // Parser flags
sip_error_t *sip_error; // Erroneous headers
sip_request_t *sip_request; // Request line
sip_status_t *sip_status; // Status line
sip_via_t *sip_via; // Via (v)
sip_route_t *sip_route; // Route
sip_record_route_t *sip_record_route; // Record-Route
sip_max_forwards_t *sip_max_forwards; // Max-Forwards
...
} sip_t;
@endcode
As you can see above, the public #sip_t structure contains the common
header members that are also found in the beginning of a header
structure. The @e sip_size indicates the size of the structure - the
application can extend the parser and #sip_t structure beyond the
original size. The @e sip_flags contains various flags used during the
parsing and printing process. They are documented in the <msg.h>. These
boilerplate members are followed by the pointers to various message
elements and headers.
@section msg_parsing_example Result of Parsing Process
Let us now show how a simple message is parsed and presented to the
applications. As an exampe, we choose a SIP request message with method BYE,
including only the mandatory fields:
@code
BYE sip:joe@example.com SIP/2.0
Via: SIP/2.0/UDP sip.example.edu;branch=d7f2e89c.74a72681
Via: SIP/2.0/UDP pc104.example.edu:1030;maddr=110.213.33.19
From: Bobby Brown <sip:bb@example.edu>;tag=77241a86
To: Joe User <sip:joe@example.com>;tag=7c6276c1
Call-ID: 4c4e911b@pc104.example.edu
CSeq: 2
@endcode
The figure below shows the layout of the BYE message above after parsing:
@image html sip-parser2.gif BYE message and its representation in C
@image latex sip-parser2.eps BYE message and its representation in C
The leftmost box represents the message of type #msg_t. Next box from
the left reprents the #sip_t structure, which contains pointers to a
header objects. The next column contains the header objects. There is
one header object for each message fragment. The rightmost box represents
the I/O buffer used when the message was received. Note that the I/O
buffer may be non-continous and composed of many separate memory areas.
The message object has link to the public message structure (@a
m_object), to the dual-linked fragment chain (@a m_frags) and to the I/O
buffer (@a m_buffer). The public message structure contains pointers to
the headers according to their type. If there are multiple headers of
the same type (like there are two Via headers in the above message), the
headers are put into a single-linked list.
Each fragment has pointers to successing and preceding fragment. It also
contains pointer to the corresponding data within the I/O buffer and its
length.
The main purpose of the fragment chain is to preserve the original order
of the headers. If there were an third Via header after CSeq in the
message, the fragment representing it would be after the CSeq header in
the fragment chain but after second Via in the header list.
@section msg_parsing_memory Example: Parsing a Complete Message
The following code fragment is an example of parsing a complete message. The
parsing process is more hairy when there is stream to be parsed.
@code
msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len)
{
msg_t *msg;
int m;
msg_iovec_t iovec[2] = {{ 0 }};
msg = msg_create(mclass, 0);
if (!msg)
return NULL;
m = msg_recv_iovec(msg, iovec, 2, n, 1);
if (m < 0) {
msg_destroy(msg);
return NULL;
}
assert(m <= 2);
assert(iovec[0].mv_len + iovec[1].mv_len == n);
memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len);
if (m == 2)
memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len);
msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1);
m = msg_extract(msg);
assert(m != 0);
if (m < 0) {
msg_destroy(msg);
return NULL;
}
return msg;
}
@endcode
Let's go through this simple function, step by step. First, we get the @a
data pointer and its size in bytes, @a len. We first initialize an I/O
vector used to represent message with the parser.
@code
msg_t *parse_memory(msg_mclass_t const *mclass, char const data[], int len)
{
msg_t *msg;
int m;
msg_iovec_t iovec[2] = {{ 0 }};
@endcode
The message class @a mclass (a parser driver object, #msg_mclass_t) is used
to represent a particular protocol-specific parser instance. When a message
object is created, it is given as an argument to msg_create() function:
@code
msg = msg_create(mclass, 0);
if (!msg)
return NULL;
@endcode
Next we obtain a memory buffer for data with msg_recv_iovec(). The memory
buffer is usually a single continous memory area, but in some cases it may
consist of two distinct areas. Therefore the @a iovec is used here to pass
the buffers around. The @a iovec is also very handly as it can be directly
passed to various system I/O calls.
@code
m = msg_recv_iovec(msg, iovec, 2, n, 1);
if (m < 0) {
msg_destroy(msg);
return NULL;
}
@endcode
These assumptions hold always true when you call msg_recv_iovec() first
time with a complete message:
@code
assert(m >= 1 && m <= 2);
assert(iovec[0].mv_len + iovec[1].mv_len == n);
@endcode
Next, we copy the data to the I/O vector and commit the copied data to the
message. Earlier with msg_recv_iovec() we allocated buffer space for data,
now calling msg_recv_commit() indicates that valid data has been copied to
the buffer. The last parameter to msg_recv_commit() indicates that the end
of stream is encountered and no more data is to be expected.
@code
memcpy(iovec[0].mv_base, data, n = iovec[0].mv_len);
if (m == 2)
memcpy(iovec[1].mv_base + n, data + n, iovec[1].mv_len);
msg_recv_commit(msg, iovec[0].mv_len + iovec[1].mv_len, 1);
@endcode
We call msg_extract() next; it takes care of parsing the message. A fatal
parsing error is indicated by returning -1. If the message is incomplete,
msg_extract() returns 0. When a complete message has been parsed, a positive
value is returned. We know that a message cannot be incomplete, as a call to
msg_recv_commit() indicated to the parser that the end-of-stream has been
encountered.
@code
m = msg_extract(msg);
assert(m != 0);
if (m < 0) {
msg_destroy(msg);
return NULL;
}
return msg;
}
@endcode
*/
/**@class msg_s msg.h
*
* @brief Message object.
*
* The message object is used by Sofia parsers for SIP and HTTP
* protocols. The message object has an abstract, protocol-independent
* inteface type #msg_t, and a separate public protocol-specific interface
* #msg_pub_t (which is typedef'ed to #sip_t or #http_t depending
* on the protocol).
*
* The main interface to abstract messages is defined in <sofia-sip/msg.h>. The
* network I/O interface used by transport protocols is defined in
* <sofia-sip/msg_addr.h>. The protocol-specific parser table, also known as message
* class, is defined in <sofia-sip/msg_mclass.h>. (The message class is used as a
* factory object when a message object is created with msg_create()).
*/
/**@typedef typedef struct msg_s msg_t;
*
* Message object.
*
* The @a msg_t is the type of a message object used by Sofia signaling
* protocols and parsers. Its contents are not directly accessible.
*/
/**@typedef typedef struct msg_common_s msg_common_t;
*
* Common part of header.
*
* The @a msg_common_t is the base type of a message headers used by
* protocol parsers. Instead of #msg_common_t, most interfaces use
* #msg_header_t, which is supposed to be a union of all possible headers.
*/
/**
* @defgroup msg_parser Parser Building Blocks
*
* This submodule contains the functions and types for building a
* protocol-specific parser.
*/
/**
* @defgroup msg_headers Headers
*
* This submodule contains the functions and types for handling message
* headers and other elements.
*/
/**
* @defgroup msg_mime MIME Headers
*
* This submodule contains the header classes, functions and types for
* handling MIME headers (@RFC2045) and MIME multipart (@RFC2046) processing.
*
* The MIME headers implemented are as follows:
* - @ref msg_accept "@b Accept header"
* - @ref msg_accept_charset "@b Accept-Charser header"
* - @ref msg_accept_encoding "@b Accept-Encoding header"
* - @ref msg_accept_language "@b Accept-Language header"
* - @ref msg_content_disposition "@b Content-Disposition header"
* - @ref msg_content_encoding "@b Content-Encoding header"
* - @ref msg_content_id "@b Content-ID header"
* - @ref msg_content_location "@b Content-Location header"
* - @ref msg_content_language "@b Content-Language header"
* - @ref msg_content_md5 "@b Content-MD5 header"
* - @ref msg_content_transfer_encoding "@b Content-Transfer-Encoding header"
* - @ref msg_mime_version "@b MIME-Version header"
*/
/**
* @defgroup test_msg Testing Parser
*
* This submodule contains the functions and types for building a
* parser objects for testing purposes.
*/
@@ -0,0 +1,156 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_parser
* @CFILE msg_auth.c
*
* Functions for handling authentication-related headers
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Jun 13 02:57:51 2000 ppessi
*
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <sofia-sip/msg.h>
#include <sofia-sip/msg_parser.h>
#include <sofia-sip/msg_header.h>
#include <sofia-sip/bnf.h>
#if 0
/**
* Scan and compact an authentication parameter.
*
* Scan an authentication parameter, which has syntax as follows:
* @code
* auth-item = auth-param | base64-string
* auth-param = token [ "=" (token | quoted-string)]
* @endcode
*
* Parameters:
* @param s pointer to string to scan
*
* @return Number of characters scanned, or zero upon an error.
*/
static size_t msg_auth_item_scan(char *start)
{
char *p, *s;
p = s = start;
/* XXX */
return start - s;
}
#endif
/* ====================================================================== */
/*
* auth = ("Authorization" | "Encryption" |
* "Proxy-Authenticate" | "Proxy-Authorization" |
* "Response-Key" | "WWW-Authenticate") ":"
* scheme 1*SP #auth-param
* scheme = token
* auth-param = token | token "=" token | token "=" quoted-string
*/
/** Parse security headers. */
issize_t msg_auth_d(su_home_t *home,
msg_header_t *h,
char *s,
isize_t slen)
{
msg_auth_t *au = (msg_auth_t *)h;
au->au_scheme = s;
skip_token(&s);
if (!IS_LWS(*s)) return -1;
*s++ = '\0'; /* NUL-terminate scheme */
return msg_commalist_d(home, &s, (msg_param_t **)&au->au_params,
NULL /* msg_auth_item_scan */);
}
issize_t msg_auth_e(char b[], isize_t bsiz, msg_header_t const *h, int f)
{
msg_auth_t const *au = (msg_auth_t *)h;
int compact = MSG_IS_COMPACT(f);
char *b0 = b, *end = b + bsiz;
MSG_STRING_E(b, end, au->au_scheme);
if (au->au_params) {
MSG_CHAR_E(b, end, ' ');
MSG_COMMALIST_E(b, end, au->au_params, compact);
}
MSG_TERM_E(b, end);
return b - b0;
}
/**@internal
* Extra size of a msg_auth_t object.
*
* This function calculates extra size required by a msg_auth_t object.
*
* @param a pointer to a msg_auth_t object
*
* @return
* Size of strings related to msg_auth_t object.
*/
isize_t msg_auth_dup_xtra(msg_header_t const *h, isize_t offset)
{
msg_auth_t const *au = h->sh_auth;
MSG_PARAMS_SIZE(offset, au->au_params);
offset += MSG_STRING_SIZE(au->au_scheme);
return offset;
}
/**Duplicate one msg_auth_t object. */
char *msg_auth_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra)
{
msg_auth_t *au = dst->sh_auth;
msg_auth_t const *o = src->sh_auth;
char *end = b + xtra;
b = msg_params_dup(&au->au_params, o->au_params, b, xtra);
MSG_STRING_DUP(b, au->au_scheme, o->au_scheme);
assert(b <= end); (void)end;
return b;
}
@@ -0,0 +1,357 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_headers
* @CFILE msg_basic.c
* @brief Basic header handling.
*
* This file contains implementation of basic headers, that is, generic
* headers like Subject or Organization containing non-structured text only,
* numeric headers like Content-Length or Max-Forwards containing only an
* 32-bit unsigned integer, or token list headers like Supported or Allow.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Feb 23 19:51:55 2001 ppessi
*/
#include "config.h"
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/msg.h>
#include <sofia-sip/bnf.h>
#include <sofia-sip/msg_parser.h>
#include <sofia-sip/msg_header.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#define msg_generic_update NULL
/* ====================================================================== */
/**@ingroup msg_headers
* @defgroup msg_error Erroneous Headers
*
* The erroneous headers are stored in #msg_error_t structure.
*
* @note Parser may put other headers (like duplicate Content-Length
* headers) into the list of erroneous headers. If the list of erroneous
* headers is processed, the header type must be validated first by calling
* msg_is_error() (or by other relevant tests).
*/
/**@ingroup msg_error
* @typedef typedef struct msg_error_s msg_error_t;
* Type for erroneous headers.
*/
isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset);
char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra);
msg_hclass_t msg_error_class[] =
MSG_HEADER_CLASS(msg_, error, "", "", er_common, append,
msg_error, msg_generic);
issize_t msg_error_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
return 0;
}
issize_t msg_error_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
/* There is no way to encode an erroneous header */
return 0;
}
isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset)
{
return msg_default_dup_xtra(h, offset);
}
char *msg_error_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra)
{
return msg_default_dup_one(dst, src, b, xtra);
}
/* ====================================================================== */
/**@ingroup msg_headers
* @defgroup msg_unknown Unknown Headers
*
* The unknown headers are handled with #msg_unknown_t structure. The whole
* unknown header including its name is included in the header value string
* @a g_value.
*
* @note It is possible to speed up parsing process by creating a parser
* which does understand only a minimum number of headers. If such a parser
* is used, some well-known headers are not regocnized or parser, but they
* are treated as unknown and put unparsed into the list of unknown headers.
*/
/**@ingroup msg_unknown
* @typedef typedef struct msg_unknown_s msg_unknown_t;
*
* Type for unknown headers.
*/
msg_hclass_t msg_unknown_class[] =
MSG_HEADER_CLASS(msg_, unknown, "", "", un_common, append,
msg_unknown, msg_generic);
issize_t msg_unknown_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
msg_unknown_t *un = (msg_unknown_t *)h;
if (msg_token_d(&s, &un->un_name) < 0 ||
*s != ':')
return -1;
*s++ = '\0';
skip_lws(&s);
un->un_value = s;
return 0;
}
issize_t msg_unknown_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
char *b0 = b, *end = b + bsiz;
msg_unknown_t *un = (msg_unknown_t *)h;
int const compact = MSG_IS_COMPACT(flags);
MSG_STRING_E(b, end, un->un_name);
MSG_CHAR_E(b, end, ':');
if (!compact) MSG_CHAR_E(b, end, ' ');
MSG_STRING_E(b, end, un->un_value);
return b - b0;
}
isize_t msg_unknown_dup_xtra(msg_header_t const *h, isize_t offset)
{
msg_unknown_t const *un = (msg_unknown_t *)h;
return offset + MSG_STRING_SIZE(un->un_name) + MSG_STRING_SIZE(un->un_value);
}
char *msg_unknown_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra)
{
msg_unknown_t *un = (msg_unknown_t *)dst;
msg_unknown_t const *o = (msg_unknown_t *)src;
char *end = b + xtra;
MSG_STRING_DUP(b, un->un_name, o->un_name);
MSG_STRING_DUP(b, un->un_value, o->un_value);
assert(b <= end); (void)end;
return b;
}
/* ====================================================================== */
/**@ingroup msg_headers
* @defgroup msg_payload Message Body
*
* The payload object contains the message body. The message body has no
* structure, but it is stored in the @a pl_data buffer as a byte array.
* Multiple payload objects may be linked to a list.
*/
/**@ingroup msg_payload
* @typedef typedef struct msg_payload_s msg_payload_t;
*
* The structure msg_payload_t contains representation of MIME message payload.
*
* The msg_payload_t is defined as follows:
* @code
* typedef struct msg_payload_s {
* msg_common_t pl_common[1]; // Common fragment info
* msg_header_t *pl_next; // Next payload object
* char *pl_data; // Data - may contain zero bytes
* usize_t pl_len; // Length of message payload
* } msg_payload_t;
* @endcode
*/
msg_hclass_t msg_payload_class[1] =
MSG_HEADER_CLASS(msg_, payload, NULL, "", pl_common, append,
msg_payload, msg_generic);
/** Create a MIME payload */
msg_payload_t *msg_payload_create(su_home_t *home, void const *data, usize_t len)
{
msg_header_t *h = msg_header_alloc(home, msg_payload_class, len + 1);
msg_payload_t *pl = h->sh_payload;
if (pl) {
char *b = msg_header_data(h->sh_common);
if (data)
memcpy(b, data, len);
else
memset(b, 0, len);
b[len] = 0;
h->sh_data = pl->pl_data = b;
h->sh_len = pl->pl_len = len;
return pl;
}
return NULL;
}
/** Parse payload. */
issize_t msg_payload_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
h->sh_payload->pl_len = slen;
h->sh_payload->pl_data = s;
h->sh_len = slen;
h->sh_data = s;
return 0;
}
issize_t msg_payload_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
size_t len = h->sh_payload->pl_len;
if (bsiz > 0) {
memcpy(b, h->sh_payload->pl_data, bsiz > len ? len : bsiz);
b[bsiz > len ? len : bsiz - 1] = '\0';
}
return len;
}
isize_t msg_payload_dup_xtra(msg_header_t const *h, isize_t offset)
{
return offset + h->sh_payload->pl_len + 1;
}
char *msg_payload_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra)
{
msg_payload_t *pl = dst->sh_payload;
msg_payload_t const *o = src->sh_payload;
memcpy(pl->pl_data = b, o->pl_data, pl->pl_len = o->pl_len);
pl->pl_common->h_data = pl->pl_data;
pl->pl_common->h_len = pl->pl_len;
pl->pl_data[pl->pl_len] = 0; /* NUL terminate just in case */
return b + pl->pl_len + 1;
}
usize_t msg_payload_length(msg_payload_t const *pl)
{
/* XXX */
return 0;
}
/* ====================================================================== */
/**@ingroup msg_headers
* @defgroup msg_separator Message Separator
*
* An empty line separates headers from the message body. In order to avoid
* modifying messages with integrity protection, the separator line has its
* own header structure which is included in the msg_t structure.
*/
/**@ingroup msg_separator
* @typedef typedef struct msg_separator_s msg_separator_t;
*
* The structure msg_separator_t contains representation of separator line
* between message headers and body.
*
* The msg_separator_t is defined as follows:
* @code
* typedef struct msg_separator_s {
* msg_common_t sep_common[1]; // Common fragment info
* msg_header_t *sep_next; // Pointer to next header
* char sep_data[4]; // NUL-terminated separator
* } msg_separator_t;
* @endcode
*/
msg_hclass_t msg_separator_class[] =
MSG_HEADER_CLASS(msg_, separator, NULL, "", sep_common, single,
msg_default, msg_generic);
/** Calculate length of line ending (0, 1 or 2). @internal */
#define CRLF_TEST(s) ((s[0]) == '\r' ? ((s[1]) == '\n') + 1 : (s[0])=='\n')
/** Parse a separator line. */
issize_t msg_separator_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
int len = CRLF_TEST(s);
if (len == 0 && slen > 0)
return -1;
memcpy(h->sh_separator->sep_data, s, len);
h->sh_separator->sep_data[len] = '\0';
return 0;
}
/** Encode a separator line. */
issize_t msg_separator_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
size_t n = strlen(h->sh_separator->sep_data);
if (bsiz > n)
strcpy(b, h->sh_separator->sep_data);
return (issize_t)n;
}
msg_separator_t *msg_separator_create(su_home_t *home)
{
msg_separator_t *sep =
msg_header_alloc(home, msg_separator_class, 0)->sh_separator;
if (sep)
strcpy(sep->sep_data, CRLF);
return sep;
}
/* ====================================================================== */
@@ -0,0 +1,413 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_parser
* @CFILE msg_date.c
* @brief Parser for HTTP-Date and HTTP-Delta.
*
* Parsing functions for @RFC1123 (GMT) date.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Wed Apr 11 18:57:06 2001 ppessi
*
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sofia-sip/msg_date.h>
#include <sofia-sip/bnf.h>
#include <sofia-sip/su_time.h>
/** Return current time as seconds since Mon, 01 Jan 1900 00:00:00 GMT. */
msg_time_t msg_now(void)
{
return su_now().tv_sec;
}
#define is_digit(c) ((c) >= '0' && (c) <= '9')
/**Epoch year. @internal
*
* First day of the epoch year should be Monday.
*/
#define EPOCH 1900
/** Is this year a leap year? @internal */
#define LEAP_YEAR(y) ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
/** Day number of New Year Day of given year. @internal */
#define YEAR_DAYS(y) \
(((y)-1) * 365 + ((y)-1) / 4 - ((y)-1) / 100 + ((y)-1) / 400)
/* ====================================================================== */
static unsigned char const days_per_months[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/** Offset of first day of the month with formula day = 30 * month + offset. */
static signed char const first_day_offset[12] =
{
0, 1, -1, 0, 0, 1, 1, 2, 3, 3, 4, 4
};
static char const wkdays[7 * 4] =
"Mon\0" "Tue\0" "Wed\0" "Thu\0" "Fri\0" "Sat\0" "Sun";
static char const months[12 * 4] =
"Jan\0" "Feb\0" "Mar\0" "Apr\0" "May\0" "Jun\0"
"Jul\0" "Aug\0" "Sep\0" "Oct\0" "Nov\0" "Dec";
/** Parse a month name.
*
* @return The function month_d() returns 0..11 if given first three letters
* of month name, or -1 if no month name matches.
*/
static inline
int month_d(char const *s)
{
unsigned const uc = ('a' - 'A') << 16 | ('a' - 'A') << 8 | ('a' - 'A');
unsigned m;
if (!s[0] || !s[1] || !s[2])
return -1;
#define MONTH_V(s) (uc | (((s[0]) << 16) + ((s[1]) << 8) + ((s[2]))))
m = MONTH_V(s);
#define MONTH_D(n) \
if (m == (uc | (months[4*(n)]<<16)|(months[4*(n)+1]<<8)|(months[4*(n)+2])))\
return (n)
MONTH_D(0);
MONTH_D(1);
MONTH_D(2);
MONTH_D(3);
MONTH_D(4);
MONTH_D(5);
MONTH_D(6);
MONTH_D(7);
MONTH_D(8);
MONTH_D(9);
MONTH_D(10);
MONTH_D(11);
return -1;
}
/* Parse SP 2DIGIT ":" 2DIGIT ":" 2DIGIT SP */
static inline
int time_d(char const **ss,
unsigned long *hour, unsigned long *min, unsigned long *sec)
{
char const *s = *ss;
if (!IS_LWS(*s))
return -1;
skip_lws(&s);
if (!is_digit(*s)) return -1;
*hour = *s++ - '0'; if (is_digit(*s)) *hour = 10 * (*hour) + *s++ - '0';
if (*s++ != ':' || !is_digit(s[0]) || !is_digit(s[1]))
return -1;
*min = 10 * s[0] + s[1] - 11 * '0'; s += 2;
if (*s++ != ':' || !is_digit(s[0]) || !is_digit(s[1]))
return -1;
*sec = 10 * s[0] + s[1] - 11 * '0'; s += 2;
if (*s) {
if (!IS_LWS(*s)) return -1; skip_lws(&s);
}
*ss = s;
return 0;
}
/**Decode RFC1123-date, RFC822-date or asctime-date.
*
* The function msg_date_d() decodes <HTTP-date>, which may have
* different formats.
*
* @code
* HTTP-date = rfc1123-date / rfc850-date / asctime-date
*
* rfc1123-date = wkday "," SP date1 SP time SP "GMT"
* date1 = 2DIGIT SP month SP 4DIGIT
* ; day month year (e.g., 02 Jun 1982)
*
* rfc850-date = weekday "," SP date2 SP time SP "GMT"
* date2 = 2DIGIT "-" month "-" 2DIGIT
* ; day-month-year (e.g., 02-Jun-82)
*
* asctime-date = wkday SP date3 SP time SP 4DIGIT
* date3 = month SP ( 2DIGIT / ( SP 1DIGIT ))
* ; month day (e.g., Jun 2)
*
* time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
* ; 00:00:00 - 23:59:59
*
* wkday = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
* weekday = "Monday" / "Tuesday" / "Wednesday"
* / "Thursday" / "Friday" / "Saturday" / "Sunday"
* month = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun"
* / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
* @endcode
*/
issize_t msg_date_d(char const **ss, msg_time_t *date)
{
char const *s = *ss;
char const *wkday;
char const *tz;
unsigned long day, year, hour, min, sec;
int mon;
if (!IS_TOKEN(*s) || !date)
return -1;
wkday = s; skip_token(&s); if (*s == ',') s++;
while (IS_LWS(*s)) s++;
if (is_digit(*s)) {
day = *s++ - '0'; if (is_digit(*s)) day = 10 * day + *s++ - '0';
if (*s == ' ') {
/* rfc1123-date =
wkday "," SP 2DIGIT SP month SP 4DIGIT SP time SP "GMT"
*/
mon = month_d(++s); skip_token(&s);
if (mon < 0 || !IS_LWS(*s)) return -1;
s++;
if (!is_digit(s[0]) || !is_digit(s[1]) ||
!is_digit(s[2]) || !is_digit(s[3]))
return -1;
year = 1000 * s[0] + 100 * s[1] + 10 * s[2] + s[3] - 1111 * '0'; s += 4;
}
else if (*s == '-') {
/* rfc822-date =
weekday "," SP 2DIGIT "-" month "-" 2DIGIT SP time SP "GMT"
*/
mon = month_d(++s);
if (mon < 0 || s[3] != '-' ||
!is_digit(s[4]) || !is_digit(s[5]))
return -1;
year = 10 * s[4] + s[5] - 11 * '0';
if (is_digit(s[6]) && is_digit(s[7])) {
/* rfc2822-date =
weekday "," SP 2DIGIT "-" month "-" 4DIGIT SP time SP "GMT"
*/
year = year * 100 + 10 * s[6] + s[7] - 11 * '0';
s += 8;
}
else {
if (year >= 70)
year = 1900 + year;
else
year = 2000 + year;
s += 6;
}
}
else
return -1;
if (time_d(&s, &hour, &min, &sec) < 0) return -1;
if (*s) {
tz = s; skip_token(&s); skip_lws(&s);
if (strncasecmp(tz, "GMT", 3) && strncasecmp(tz, "UCT", 3))
return -1;
}
}
else {
/* actime-date =
wkday SP month SP ( 2DIGIT | ( SP 1DIGIT )) SP time SP 4DIGIT */
mon = month_d(s); skip_token(&s);
if (mon < 0 || !IS_LWS(*s)) return -1; s++;
while (IS_LWS(*s)) s++;
if (!is_digit(*s)) return -1;
day = *s++ - '0'; if (is_digit(*s)) day = 10 * day + *s++ - '0';
if (time_d(&s, &hour, &min, &sec) < 0) return -1;
/* Accept also unix date (if it is GMT) */
if ((s[0] == 'G' && s[1] == 'M' && s[2] == 'T' && s[3] == ' ') ||
(s[0] == 'U' && s[1] == 'T' && s[2] == 'C' && s[3] == ' '))
s += 4;
else if (s[0] == 'U' && s[1] == 'T' && s[2] == ' ')
s += 3;
if (!is_digit(s[0]) || !is_digit(s[1]) ||
!is_digit(s[2]) || !is_digit(s[3]))
return -1;
year = 1000 * s[0] + 100 * s[1] + 10 * s[2] + s[3] - 1111 * '0'; s += 4;
}
if (hour > 24 || min >= 60 || sec >= 60 ||
(hour == 24 && min > 0 && sec > 0))
return -1;
if (day == 0 || day > days_per_months[mon]) {
if (day != 29 || mon != 1 || !LEAP_YEAR(year))
return -1;
}
if (year < EPOCH) {
*date = 0;
}
else if (year > EPOCH + 135) {
*date = 0xfdeefb80; /* XXX: EPOCH + 135 years */
}
else {
int leap_year = LEAP_YEAR(year);
msg_time_t ydays = YEAR_DAYS(year) - YEAR_DAYS(EPOCH);
#if 0
printf("Year %d%s starts %ld = %d - %d days since epoch (%d)\n",
year, leap_year ? " (leap year)" : "",
ydays, YEAR_DAYS(year), YEAR_DAYS(EPOCH), EPOCH);
#endif
*date = sec + 60 *
(min + 60 *
(hour + 24 *
(day - 1 + mon * 30 + first_day_offset[mon] +
(leap_year && mon > 2) + ydays)));
}
*ss = s;
return 0;
}
/**Encode RFC1123-date.
*
* The function msg_date_e() prints @e http-date in the <rfc1123-date>
* format. The format is as follows:
*
* @code
* rfc1123-date = wkday "," SP date SP time SP "GMT"
* wkday = "Mon" | "Tue" | "Wed"
* | "Thu" | "Fri" | "Sat" | "Sun"
* date = 2DIGIT SP month SP 4DIGIT
* ; day month year (e.g., 02 Jun 1982)
* month = "Jan" | "Feb" | "Mar" | "Apr"
* | "May" | "Jun" | "Jul" | "Aug"
* | "Sep" | "Oct" | "Nov" | "Dec"
* time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
* ; 00:00:00 - 23:59:59
* @endcode
*
* @param b buffer to print the date
* @param bsiz size of the buffer
* @param http_date seconds since 01 Jan 1900.
*
* @return The function msg_date_e() returns the size of the formatted date.
*/
issize_t msg_date_e(char b[], isize_t bsiz, msg_time_t http_date)
{
msg_time_t sec, min, hour, wkday, day, month, year;
msg_time_t days_per_month, leap_year;
sec = http_date % 60; http_date /= 60;
min = http_date % 60; http_date /= 60;
hour = http_date % 24; http_date /= 24;
wkday = http_date % 7;
day = http_date + YEAR_DAYS(EPOCH);
year = EPOCH + http_date / 365;
for (;;) {
if (day >= YEAR_DAYS(year + 1))
year++;
else if (day < YEAR_DAYS(year))
year--;
else
break;
}
day -= YEAR_DAYS(year);
leap_year = LEAP_YEAR(year);
month = 0, days_per_month = 31;
while (day >= days_per_month) {
day -= days_per_month;
month++;
days_per_month = days_per_months[month] + (leap_year && month == 2);
}
return snprintf(b, bsiz, "%s, %02ld %s %04ld %02ld:%02ld:%02ld GMT",
wkdays + wkday * 4, day + 1, months + month * 4,
year, hour, min, sec);
}
/**Decode a delta-seconds.
*
* The function msg_delta_d() decodes a <delta-seconds> field.
*
* The <delta-seconds> is defined as follows:
* @code
* delta-seconds = 1*DIGIT
* @endcode
*
* Note, however, that <delta-seconds> may not be larger than #MSG_TIME_MAX.
*/
issize_t msg_delta_d(char const **ss, msg_time_t *delta)
{
char const *s = *ss;
if (!is_digit(*s))
return -1;
*delta = strtoul(*ss, (char **)ss, 10);
skip_lws(ss);
return *ss - s;
}
/**Encode @ref msg_delta_d() "<delta-seconds>" field.
*/
issize_t msg_delta_e(char b[], isize_t bsiz, msg_time_t delta)
{
return snprintf(b, bsiz, "%lu", (unsigned long)delta);
}
/** Decode a HTTP date or delta
*
* Decode a @ref msg_date_d() "<http-date>" or
* @ref msg_delta_d() "<delta-seconds>" field.
*/
issize_t msg_date_delta_d(char const **ss,
msg_time_t *date,
msg_time_t *delta)
{
if (delta && is_digit(**ss)) {
return msg_delta_d(ss, delta);
}
else if (date && IS_TOKEN(**ss)) {
return msg_date_d(ss, date);
}
return -1;
}
@@ -0,0 +1,234 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_parser
* @file msg_generic.c
* @brief Functions for generic headers
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jan 23 20:08:00 2003 ppessi
*
*/
#include "config.h"
#include <sofia-sip/su_alloc.h>
#include "sofia-sip/msg.h"
#include "sofia-sip/bnf.h"
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_header.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
/**
* Parse a generic header.
*
* The function msg_generic_d() parses a generic header structure.
*
* @param[in] home memory home
* @param[in,out] h header structure
* @param[in] s string to be parsed
* @param[in] slen length of the string
*
* @retval 0 when successful,
* @retval -1 upon an error.
*/
issize_t msg_generic_d(su_home_t *home,
msg_header_t *h,
char *s,
isize_t slen)
{
h->sh_generic->g_string = s;
return 0;
}
/**
* Encode a generic header.
*
* The function @c msg_generic_e encodes a generic header.
*
*/
issize_t msg_generic_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
msg_generic_t const *g = h->sh_generic;
size_t n = strlen(g->g_string);
if (bsiz > n)
strcpy(b, g->g_string);
return (issize_t)n;
}
/** Calculate the size of strings associated with a @c msg_generic_t object. */
isize_t msg_generic_dup_xtra(msg_header_t const *h, isize_t offset)
{
msg_generic_t const *g = h->sh_generic;
return offset + MSG_STRING_SIZE(g->g_string);
}
/** Duplicate one @c msg_generic_t object. */
char *msg_generic_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra)
{
char *end = b + xtra;
MSG_STRING_DUP(b, dst->sh_generic->g_string, src->sh_generic->g_string);
assert(b <= end); (void)end;
return b;
}
issize_t msg_numeric_d(su_home_t *home,
msg_header_t *h,
char *s,
isize_t slen)
{
uint32_t value = 0;
issize_t retval = msg_uint32_d(&s, &value);
h->sh_numeric->x_value = value;
if (*s)
return -1;
return retval;
}
issize_t msg_numeric_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
uint32_t value = h->sh_numeric->x_value;
if (h->sh_numeric->x_value > 0xffffffff)
return -1;
return snprintf(b, bsiz, "%lu", (unsigned long)value);
}
/* ====================================================================== */
/* Comma-separated list */
/** @typedef struct msg_list_s msg_list_t;
*
* Type for token list headers.
*
*/
issize_t msg_list_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
return msg_commalist_d(home, &s, &h->sh_list->k_items, NULL);
}
issize_t msg_list_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
int compact = MSG_IS_COMPACT(flags);
char *b0 = b, *end = b + bsiz;
MSG_COMMALIST_E(b, end, h->sh_list->k_items, compact);
MSG_TERM_E(b, end);
return b - b0;
}
/**@internal
* Extra size of a msg_auth_t object.
*
* This function calculates extra size required by a msg_auth_t object.
*
* @param a pointer to a msg_auth_t object
*
* @return
* Size of strings related to msg_auth_t object.
*/
isize_t msg_list_dup_xtra(msg_header_t const *h, isize_t offset)
{
MSG_PARAMS_SIZE(offset, h->sh_list->k_items);
return offset;
}
char *msg_list_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra)
{
char *end = b + xtra;
msg_param_t const ** items = (msg_param_t const **)&dst->sh_list->k_items;
b = msg_params_dup(items, src->sh_list->k_items, b, xtra);
assert(b <= end); (void)end;
return b;
}
/** Append a list of constant items to a list.
*
* @retval 0 when successful
* @retval -1 upon an error
*/
int msg_list_append_items(su_home_t *home,
msg_list_t *k,
msg_param_t const items[])
{
size_t i;
if (k == NULL) return -1;
if (items == NULL) return 0;
for (i = 0; items[i]; i++) {
if (msg_header_add_param(home, (msg_common_t *)k, items[i]) < 0)
return -1;
}
return 0;
}
/** Replace a list of constant items.
*
* @retval 0 when successful
* @retval -1 upon an error
*/
int msg_list_replace_items(su_home_t *home,
msg_list_t *k,
msg_param_t const items[])
{
size_t i;
if (k == NULL) return -1;
if (items == NULL) return 0;
for (i = 0; items[i]; i++) {
if (msg_header_replace_item(home, (msg_common_t *)k, items[i]) < 0)
return -1;
}
return 0;
}
@@ -0,0 +1,534 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_headers
* @CFILE msg_header_copy.c
*
* Copying and duplicating headers structures.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Jun 13 02:57:51 2000 ppessi
*
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/su.h>
#include "msg_internal.h"
#include "sofia-sip/msg.h"
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_header.h"
/** Calculate size of a parameter vector */
static inline
size_t msg_params_copy_xtra(msg_param_t const pp[], size_t offset)
{
size_t n = msg_params_count(pp);
if (n) {
MSG_STRUCT_SIZE_ALIGN(offset);
offset += MSG_PARAMS_NUM(n + 1) * sizeof(pp[0]);
}
return offset;
}
/** Copy a vector of parameters */
static inline
char *msg_params_copy(char *b, size_t size,
msg_param_t **dst,
msg_param_t const src[])
{
size_t n = msg_params_count(src);
if (n) {
MSG_STRUCT_ALIGN(b);
*dst = memcpy(b, src, (n + 1) * sizeof(src[0]));
b += MSG_PARAMS_NUM(n + 1) * sizeof(src[0]);
}
else {
*dst = NULL;
}
return b;
}
/**Copy a header object.
*
* The function @c msg_header_copy_as() shallowly copies a header object.
*
* @param home pointer to the memory home
* @param hc header class for the copied header
* @param src pointer to a header object
*
* @return
* The function @c msg_header_copy_as() returns a pointer to the the shallow copy
* of the header object, or @c NULL upon an error.
*/
static msg_header_t *msg_header_copy_one_as(su_home_t *home,
msg_hclass_t *hc,
msg_header_t const *src)
{
msg_header_t *h;
size_t size = hc->hc_size, xtra;
msg_param_t const *params;
char *end;
if (hc->hc_params) {
params = *(msg_param_t const **)((char const *)src + hc->hc_params);
xtra = msg_params_copy_xtra(params, size) - size;
}
else {
params = NULL;
xtra = 0;
}
if (!(h = msg_header_alloc(home, hc, (isize_t)xtra)))
return NULL; /* error */
memcpy(&h->sh_data, &src->sh_data, size - offsetof(msg_common_t, h_data));
h->sh_next = NULL;
if (params) {
msg_param_t **pparams = (msg_param_t **)((char *)h + hc->hc_params);
end = msg_params_copy((char *)h + size, xtra, pparams, params);
if (!end) {
su_free(home, h);
return NULL;
}
}
else
end = (char *)h + size;
assert(end == (char *)h + xtra + size);
return h;
}
/**Copy a list of header objects.
*
* The function @c msg_header_copy_as() shallowly copies a list of header
* objects, and casts them to the given header class.
*
* @param home pointer to the memory home
* @param hc header class
* @param src pointer to a list of header objects to be copied
*
* @return The function @c msg_header_copy_as() returns a pointer to the
* first of the copied msg header object(s), or @c NULL upon an error.
*/
msg_header_t *msg_header_copy_as(su_home_t *home,
msg_hclass_t *hc,
msg_header_t const *src)
{
msg_header_t *h, *rv = NULL, *prev = NULL;
if (src == NULL || src == MSG_HEADER_NONE)
return NULL;
if (hc == NULL)
hc = src->sh_class;
for (; src; src = src->sh_next, prev = h) {
if (!(h = msg_header_copy_one_as(home, hc, src)))
break;
if (!rv)
rv = h;
else
prev->sh_next = h;
}
if (src) {
/* Copy was not successful, free all copied headers in list */
for (;rv; rv = h) {
h = rv->sh_next;
su_free(home, rv);
}
}
return rv;
}
/** Copy a single header. */
msg_header_t *msg_header_copy_one(su_home_t *home, msg_header_t const *src)
{
assert(MSG_HEADER_TEST(src));
if (!src || !src->sh_class)
return NULL;
return msg_header_copy_one_as(home, src->sh_class, src);
}
/** Copy a header list. */
msg_header_t *msg_header_copy(su_home_t *home, msg_header_t const *src)
{
assert(MSG_HEADER_TEST(src));
if (!src || !src->sh_class)
return NULL;
return msg_header_copy_as(home, src->sh_class, src);
}
/** Duplicate a sigle header.
*
* Deeply copy a single header.
*
* @param home pointer to the memory home
* @param src pointer to asingle header object to be copied
*
* @return Return a pointer to the
* the duplicated msg header object(s), or @c NULL upon an error.
*/
msg_header_t *msg_header_dup_one(su_home_t *home,
msg_header_t const *src)
{
msg_hclass_t *hc;
size_t size, xtra;
msg_header_t *h;
char *end;
if (src == NULL || src == MSG_HEADER_NONE)
return NULL;
hc = src->sh_class;
assert(hc);
size = hc->hc_size;
xtra = hc->hc_dxtra(src, size) - size;
if (!(h = msg_header_alloc(home, hc, xtra)))
return NULL;
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra))) {
su_free(home, h);
return NULL;
}
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
return h;
}
/** Duplicate a header as class @a hc.
*
* The function @c msg_header_dup_as() casts a list of header headers to
* given type, and then deeply copies the list.
*
* @param home pointer to the memory home
* @param hc header class
* @param src pointer to a list of header objects to be copied
*
* @return The function @c msg_header_copy_as() returns a pointer to the
* first of the copied msg header object(s), or @c NULL upon an error.
*/
msg_header_t *msg_header_dup_as(su_home_t *home, msg_hclass_t *hc,
msg_header_t const *src)
{
msg_header_t *h, *rv = NULL, **prev;
if (src == NULL || src == MSG_HEADER_NONE)
return NULL;
if (hc == NULL)
hc = src->sh_class;
assert(hc);
for (prev = &rv; src; src = src->sh_next, prev = &h->sh_next) {
size_t size = hc->hc_size;
size_t xtra = hc->hc_dxtra(src, size) - size;
char *end;
if (!(h = msg_header_alloc(home, hc, (isize_t)xtra)))
break; /* error */
if (!rv)
rv = h;
if (!(end = hc->hc_dup_one(h, src, (char *)h + size, xtra)))
break; /* error */
if (hc->hc_update)
msg_header_update_params(h->sh_common, 1);
assert(end == (char *)h + size + xtra);
*prev = h;
}
if (src) {
/* Copy was not successful, free all duplicated headers in list */
for (;rv; rv = h) {
h = rv->sh_next;
su_free(home, rv);
}
}
return rv;
}
/** Duplicate a header list.
*
* The function @c msg_header_dup() deeply copies a list of message headers
* objects.
*
* @param home pointer to the memory home
* @param h pointer to a list of header objects to be copied
*
* @return The function @c msg_header_dup() returns a pointer to the first
* of the copied message header object(s), or @c NULL upon an error.
*/
msg_header_t *msg_header_dup(su_home_t *home, msg_header_t const *h)
{
if (h == NULL || h == MSG_HEADER_NONE)
return NULL;
assert(MSG_HEADER_TEST(h));
return msg_header_dup_as(home, h->sh_class, h);
}
/** Calculate extra size of a plain header. */
isize_t msg_default_dup_xtra(msg_header_t const *header, isize_t offset)
{
return offset;
}
/**Duplicate a header object without external references.
*
* The function @c msg_default_dup_one() copies the contents of header
* object @a src to @a h. The header object should not contain external
* references (pointers).
*
* @param h pointer to newly allocated header object
* @param src pointer to a header object to be duplicated
* @param b memory buffer used to copy (not used)
* @param xtra number bytes in buffer @a b (not used)
*
* @return The function @c msg_default_dup_one() returns a pointer to the
* memory buffer @a b.
*/
char *msg_default_dup_one(msg_header_t *h,
msg_header_t const *src,
char *b,
isize_t xtra)
{
memcpy(&h->sh_header_next[1],
&src->sh_header_next[1],
h->sh_class->hc_size - offsetof(msg_header_t, sh_header_next[1]));
return b;
}
/* ====================================================================== */
/* Copying or duplicating all headers in a message */
static int msg_copy_chain(msg_t *msg, msg_t const *copied);
static int msg_dup_or_copy_all(msg_t *msg,
msg_t const *original,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *));
/**Copy a message shallowly.
*
* @relatesalso msg_s
*
* Copy a message and the header structures. The copied message will share
* all the strings with the original message. It will keep a reference to
* the original message, and the original message is not destroyed until all
* the copies have been destroyed.
*
* @param original message to be copied
*
* @retval pointer to newly copied message object when successful
* @retval NULL upon an error
*/
msg_t *msg_copy(msg_t *original)
{
if (original) {
msg_t *copy = msg_create(original->m_class, original->m_object->msg_flags);
if (copy) {
if (original->m_chain
? msg_copy_chain(copy, original) < 0
: msg_dup_or_copy_all(copy, original, msg_header_copy_one) < 0) {
msg_destroy(copy), copy = NULL;
}
else
msg_set_parent(copy, original);
return copy;
}
}
return NULL;
}
/** Copy header chain.
*
* @retval 0 when successful
* @retval -1 upon an error
*/
static
int msg_copy_chain(msg_t *msg, msg_t const *original)
{
su_home_t *home = msg_home(msg);
msg_pub_t *dst = msg->m_object;
msg_header_t **tail;
msg_header_t *dh;
msg_header_t const *sh;
msg_header_t **hh;
tail = msg->m_tail;
for (sh = original->m_chain; sh; sh = (msg_header_t const *)sh->sh_succ) {
hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
if (!hh)
break;
while (*hh)
hh = &(*hh)->sh_next;
dh = msg_header_copy_one(home, sh);
if (!dh)
break;
dh->sh_prev = tail, *tail = dh, tail = &dh->sh_succ;
*hh = dh;
}
msg->m_tail = tail;
if (sh)
return -1;
return 0;
}
/**Deep copy a message.
*
* @relatesalso msg_s
*
* Copy a message, the header structures and all the related strings. The
* duplicated message does not share any (non-const) data with original.
* Note that the cached representation (in h_data) is not copied.
*
* @param original message to be duplicated
*
* @retval pointer to newly duplicated message object when successful
* @retval NULL upon an error
*/
msg_t *msg_dup(msg_t const *original)
{
if (original) {
msg_t *dup = msg_create(original->m_class, original->m_object->msg_flags);
if (dup && msg_dup_or_copy_all(dup, original, msg_header_dup_one) < 0) {
msg_destroy(dup), dup = NULL;
}
return dup;
}
return NULL;
}
/** Copy a complete message, not keeping the header chain structure.
*
* @retval 0 when successful
* @retval -1 upon an error
*/
static
int msg_dup_or_copy_all(msg_t *msg,
msg_t const *original,
msg_header_t *(*copy_one)(su_home_t *h,
msg_header_t const *))
{
su_home_t *home = msg_home(msg);
msg_pub_t *dst = msg->m_object;
msg_pub_t const *src = original->m_object;
msg_header_t * const *ssh;
msg_header_t * const *end;
msg_header_t const *sh;
msg_header_t **hh;
msg_header_t *h;
assert(copy_one);
end = (msg_header_t**)((char *)src + src->msg_size);
for (ssh = &src->msg_request; ssh < end; ssh++) {
sh = *ssh;
if (!sh)
continue;
hh = msg_hclass_offset(msg->m_class, dst, sh->sh_class);
if (hh == NULL)
return -1;
for (; sh; sh = sh->sh_next) {
h = copy_one(home, sh);
if (h == NULL)
return -1;
if (*hh) {
/* If there is multiple instances of single headers,
put the extra headers into the list of erroneous headers */
if (msg_is_single(h)) {
msg_error_t **e;
for (e = &dst->msg_error; *e; e = &(*e)->er_next)
;
*e = (msg_error_t *)h;
continue;
}
while (*hh)
hh = &(*hh)->sh_next;
}
*hh = h;
if (msg_is_list(sh))
/* Copy only first list entry */
break;
}
}
return 0;
}
@@ -0,0 +1,180 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_headers
* @CFILE msg_header_make.c
*
* Creating message headers from strings.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Feb 23 14:06:34 2001 ppessi
*
*/
#include "config.h"
#include <sofia-sip/su_alloc.h>
#include "sofia-sip/msg.h"
#include "sofia-sip/bnf.h"
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_header.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <errno.h>
#if defined(va_copy)
/* Xyzzy */
#elif defined(__va_copy)
#define va_copy(dst, src) __va_copy((dst), (src))
#else
#define va_copy(dst, src) (memcpy(&(dst), &(src), sizeof (va_list)))
#endif
#include <assert.h>
/** Make a header from a value string. */
msg_header_t *msg_header_make(su_home_t *home,
msg_hclass_t *hc,
char const *s)
{
size_t xtra;
msg_header_t *h;
int normal = hc->hc_name ||
(hc->hc_hash != msg_payload_hash &&
hc->hc_hash != msg_separator_hash &&
hc->hc_hash != msg_error_hash);
if (s == NULL)
return NULL;
/* For normal headers, strip LWS from both ends */
if (normal)
skip_lws(&s);
xtra = strlen(s);
if (normal)
while (xtra > 0 && IS_LWS(s[xtra - 1]))
xtra--;
h = msg_header_alloc(home, hc, xtra + 1);
if (h) {
char *b = MSG_HEADER_DATA(h);
strncpy(b, s, xtra)[xtra] = 0;
if (hc->hc_parse(home, h, b, xtra) == -1) {
/* Note: parsing function is responsible to free
everything it has allocated (like parameter lists) */
/* XXX - except header structures */
su_free(home, h), h = NULL;
}
}
return h;
}
/** Make a MSG header with formatting provided. */
msg_header_t *msg_header_vformat(su_home_t *home,
msg_hclass_t *hc,
char const *fmt,
va_list ap)
{
msg_header_t *h;
int n;
size_t xtra = 64; /* reasonable default */
/* Quick path */
if (!fmt || !strchr(fmt, '%'))
return msg_header_make(home, hc, fmt);
/* Another quickie */
if (strcmp(fmt, "%s") == 0) {
fmt = va_arg(ap, char const *);
return msg_header_make(home, hc, fmt);
}
if (!(h = msg_header_alloc(home, hc, xtra)))
return NULL;
for (;;) {
va_list aq;
va_copy(aq, ap);
n = vsnprintf(MSG_HEADER_DATA(h), xtra, fmt, aq);
va_end(aq);
if (n >= 0 && (size_t)n < xtra)
break;
/* Try again with more space */
su_free(home, h);
if (xtra >= INT_MAX)
return NULL;
if (n >= 0)
xtra = n + 1; /* precisely what is needed */
else
xtra *= 2; /* glibc 2.0 - twice the old size */
if (xtra > INT_MAX)
xtra = INT_MAX;
if (!(h = msg_header_alloc(home, hc, xtra)))
return NULL;
}
if (hc->hc_parse(home, h, MSG_HEADER_DATA(h), (size_t)n) == -1) {
/* Note: parsing function is responsible to free
everything it has allocated (like parameter lists) */
su_free(home, h), h = NULL;
}
return h;
}
msg_header_t *msg_header_format(su_home_t *home,
msg_hclass_t *hc,
char const *fmt,
...)
{
msg_header_t *h;
va_list ap;
va_start(ap, fmt);
h = msg_header_vformat(home, hc, fmt, ap);
va_end(ap);
return h;
}
@@ -0,0 +1,151 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_INTERNAL_H
/** Defined when <msg_internal.h> has been included. */
#define MSG_INTERNAL_H
/**@IFILE msg_internal.h
* @brief Abstract messages - internal interface
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jun 29 15:58:06 2000 ppessi
*
*/
#ifdef MSG_H
#error "msg_internal.h" should be included before "msg.h"
#endif
#include "sofia-sip/msg.h"
#include "sofia-sip/msg_addr.h"
#include "sofia-sip/msg_buffer.h"
#ifndef SU_ALLOC_H
#include <sofia-sip/su_alloc.h>
#endif
SOFIA_BEGIN_DECLS
/* ---------------------------------------------------------------------- */
/* Types used when handling streaming */
typedef struct msg_buffer_s msg_buffer_t;
/* ---------------------------------------------------------------------- */
struct msg_s {
su_home_t m_home[1]; /**< Memory home */
msg_mclass_t const *m_class; /**< Message class */
int m_oflags; /**< Original flags */
msg_pub_t *m_object; /**< Public view to parsed message */
size_t m_maxsize;/**< Maximum size */
size_t m_size; /**< Total size of fragments */
msg_header_t *m_chain; /**< Fragment chain */
msg_header_t **m_tail; /**< Tail of fragment chain */
msg_payload_t *m_chunk; /**< Incomplete payload fragment */
/* Parsing/printing buffer */
struct msg_mbuffer_s {
char *mb_data; /**< Pointer to data */
usize_t mb_size; /**< Size of buffer */
usize_t mb_used; /**< Used data */
usize_t mb_commit; /**< Data committed to msg */
unsigned mb_eos:1; /**< End-of-stream flag */
unsigned :0;
} m_buffer[1];
msg_buffer_t *m_stream; /**< User-provided buffers */
size_t m_ssize; /**< Stream size */
unsigned short m_extract_err; /**< Bitmask of erroneous headers */
/* Internal flags */
unsigned m_set_buffer:1;/**< Buffer has been set */
unsigned m_streaming:1; /**< Use streaming with message */
unsigned m_prepared:1; /**< Prepared/not */
unsigned :0;
msg_t *m_next; /**< Next message */
msg_t *m_parent; /**< Reference to a parent message */
int m_refs; /**< Number of references to this message */
su_addrinfo_t m_addrinfo; /**< Message addressing info (protocol) */
su_sockaddr_t m_addr[1]; /**< Message address */
int m_errno; /**< Errno */
};
/** Buffer for message body. */
struct msg_buffer_s {
char *b_data; /**< Data - may contain NUL */
size_t b_size; /**< Length of message payload */
size_t b_used; /**< Used data */
size_t b_avail; /**< Available data */
int b_complete; /**< This buffer completes the message */
msg_buffer_t *b_next; /**< Next buffer */
msg_payload_t *b_chunks; /**< List of body chunks */
};
/** Maximum size when streaming. */
#define MSG_SSIZE_MAX (USIZE_MAX)
/* ---------------------------------------------------------------------- */
/* Header-kind predicate functions. */
static inline int msg_is_single(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_single;
}
static inline int msg_is_prepend(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_prepend;
}
static inline int msg_is_append(msg_header_t const *h)
{
return
h->sh_class->hc_kind == msg_kind_append ||
h->sh_class->hc_kind == msg_kind_apndlist;
}
static inline int msg_is_list(msg_header_t const *h)
{
return h->sh_class->hc_kind == msg_kind_list;
}
static inline int msg_is_special(msg_header_t const *h)
{
return h->sh_class->hc_hash < 0;
}
SOFIA_END_DECLS
#endif /* MSG_INTERNAL_H */
@@ -0,0 +1,387 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_parser
* @CFILE msg_mclass.c
*
* Message factory object.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Wed Jun 5 14:34:24 2002 ppessi
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>
#include <stdarg.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/su.h>
#include <sofia-sip/su_alloc.h>
#include "msg_internal.h"
#include "sofia-sip/msg_parser.h"
#include "sofia-sip/msg_mclass.h"
#include "sofia-sip/msg_mclass_hash.h"
/** Clone a message class.
*
* @relatesalso msg_mclass_s
*
* The function msg_mclass_clone() makes a copy of message class object @a
* old. It is possible to resize the hash table by giving a non-zero @a
* newsize. If @a newsize is 0, the size of hash table is not changed. If @a
* empty is true, the copied message class object will not recognize any
* headers. This is useful if more fine-grained control of parsing process
* is required, for instance.
*
* @param[in] old pointer to the message class object to be copied
* @param[in] newsize size of hash table in the copied object
* @param[in] empty if true, resulting copy does not contain any headers
*
* @return
* The function msg_mclass_clone() returns a pointer to a newly
* copied message class object, or NULL upon an error.
* The returned message class object can be freed with free().
*
* @ERRORS
* @ERROR ENOMEM
* A memory allocation failed.
* @ERROR EINVAL
* The function was given invalid arguments.
*
* @note The empty parser can handle request/status line. All headers are
* put into list of unknown headers (unless they are malformed, and they are
* put into list of erronous headers). However, SIP, RTSP, and HTTP
* protocols all require that the parser recognizes @b Content-Length header
* before they can extract the message body from the data received from
* network.
*
*/
msg_mclass_t *msg_mclass_clone(msg_mclass_t const *old, int newsize, int empty)
{
size_t size, shortsize;
msg_mclass_t *mc;
int identical;
unsigned short i;
if (newsize == 0)
newsize = old->mc_hash_size;
if (newsize < old->mc_hash_used ||
(unsigned)newsize > USHRT_MAX / sizeof(msg_header_t *)) {
errno = EINVAL;
return NULL;
}
size = offsetof(msg_mclass_t, mc_hash[newsize]);
if (old->mc_short)
shortsize = MC_SHORT_SIZE * (sizeof old->mc_short[0]);
else
shortsize = 0;
mc = malloc(size + shortsize);
identical = newsize == old->mc_hash_size && !empty;
if (mc) {
if (!identical) {
memcpy(mc, old, offsetof(msg_mclass_t, mc_hash));
memset(mc->mc_hash, 0, size - offsetof(msg_mclass_t, mc_hash));
mc->mc_short = NULL;
mc->mc_hash_size = newsize;
mc->mc_hash_used = 0;
for (i = 0; !empty && i < old->mc_hash_size; i++) {
msg_mclass_insert(mc, &old->mc_hash[i]);
}
}
else {
memcpy(mc, old, size);
mc->mc_short = NULL;
}
if (shortsize) {
if (empty)
mc->mc_short = memset((char *)mc + size, 0, shortsize);
else
mc->mc_short = memcpy((char *)mc + size, old->mc_short, shortsize);
}
}
return mc;
}
/**Add a new header to the message class.
*
* @relatesalso msg_mclass_s
*
* Insert a header class @a hc to the message class object @a mc. If the
* given @a offset of the header in @ref msg_pub_t "public message
* structure" is zero, the function extends the public message structure in
* order to store newly inserted header there.
*
* @param[in,out] mc pointer to a message class object
* @param[in] hc pointer to a header class object
* @param[in] offset offset of the header in
* @ref msg_pub_t "public message structure"
*
* If the @a offset is 0, the msg_mclass_insert_header() increases size of
* the public message structure and places the header at the end of message.
*
* @return Number of collisions in hash table, or -1 upon an error.
*
* @deprecated Use msg_mclass_insert_with_mask() instead.
*/
int msg_mclass_insert_header(msg_mclass_t *mc,
msg_hclass_t *hc,
unsigned short offset)
{
msg_href_t hr[1];
if (mc == NULL || hc == NULL) {
errno = EINVAL;
return -1;
}
if (msg_hclass_offset(mc, NULL, hc))
return (void)(errno = EEXIST), -1;
if (offset == 0)
offset = mc->mc_msize, mc->mc_msize += sizeof(msg_header_t *);
assert(offset < mc->mc_msize);
hr->hr_class = hc;
hr->hr_offset = offset;
return msg_mclass_insert(mc, hr);
}
/**Add a new header to the message class.
*
* @relatesalso msg_mclass_s
*
* Insert a header class @a hc to the message class @a mc. If the given @a
* offset of the header in @ref msg_pub_t "public message structure" is
* zero, extend the size of the public message structure in order to store
* headers at the end of structure.
*
* @param[in,out] mc pointer to a message class
* @param[in] hc pointer to a header class
* @param[in] offset offset of the header in
* @ref msg_pub_t "public message structure"
* @param[in] flags classification flags for the header
*
* @return Number of collisions in hash table, or -1 upon an error.
*/
int msg_mclass_insert_with_mask(msg_mclass_t *mc,
msg_hclass_t *hc,
unsigned short offset,
unsigned short flags)
{
msg_href_t hr[1];
if (mc == NULL || hc == NULL) {
errno = EINVAL;
return -1;
}
if (msg_hclass_offset(mc, NULL, hc))
return (void)(errno = EEXIST), -1;
if (offset == 0)
offset = mc->mc_msize, mc->mc_msize += sizeof(msg_header_t *);
assert(offset < mc->mc_msize);
hr->hr_class = hc;
hr->hr_offset = offset;
hr->hr_flags = flags;
return msg_mclass_insert(mc, hr);
}
/** Add a header reference to the message class.
*
* @relatesalso msg_mclass_s
*
* @param[in,out] mc pointer to a message class object
* @param[in] hr header reference object
*
* @return Number of collisions in hash table, or -1 upon an error.
*/
int msg_mclass_insert(msg_mclass_t *mc, msg_href_t const *hr)
{
int j, j0;
int N;
int collisions = 0;
msg_hclass_t *hc;
if (mc == NULL) {
errno = EINVAL;
return -1;
}
if (hr == NULL || (hc = hr->hr_class) == NULL)
return 0;
/* Add short form */
if (mc->mc_short && hc->hc_short[0]) {
char compact = hc->hc_short[0];
msg_href_t *shorts = (msg_href_t *)mc->mc_short;
if (compact < 'a' || compact > 'z')
return -1;
if (shorts[compact - 'a'].hr_class &&
shorts[compact - 'a'].hr_class != hc)
return -1;
shorts[compact - 'a'] = *hr;
}
N = mc->mc_hash_size;
j0 = msg_header_name_hash(hc->hc_name, NULL) % N;
for (j = j0; mc->mc_hash[j].hr_class; ) {
collisions++;
if (mc->mc_hash[j].hr_class == hc)
return -1;
j = (j + 1) % N;
if (j == j0)
return -1;
}
mc->mc_hash[j] = hr[0];
mc->mc_hash_used++;
return collisions;
}
/** Calculate length of line ending (0, 1 or 2). @internal */
#define CRLF_TEST(cr, lf) ((cr) == '\r' ? ((lf) == '\n') + 1 : (cr)=='\n')
/**Search for a header class.
*
* @relatesalso msg_mclass_s
*
* The function msg_find_hclass() searches for a header class from a message
* class based on the contents of the header to be parsed. The buffer @a s
* should point to the first character in the header name.
*
* @param[in] mc message class object
* @param[in] s header contents
* @param[out] return_start_of_content start of header content (may be NULL)
*
* @return The function msg_find_hclass() returns a pointer to a header
* reference structure. A pointer to a header reference for unknown headers
* is returned, if the header is not included in the message class.
*
* @par
* The return-value parameter @a return_start_of_content will contain the
* start of the header contents within @a s, or 0 upon an error parsing the
* header name and following colon.
*
* @par
* Upon a fatal error, a NULL pointer is returned.
*/
msg_href_t const *msg_find_hclass(msg_mclass_t const *mc,
char const *s,
isize_t *return_start_of_content)
{
msg_href_t const *hr;
short i, N, m;
isize_t len;
assert(mc);
N = mc->mc_hash_size;
i = msg_header_name_hash(s, &len) % N;
if (len == 0 || len > HC_LEN_MAX) {
if (return_start_of_content)
*return_start_of_content = 0;
return mc->mc_error;
}
m = (short)len;
if (m == 1 && mc->mc_short) {
short c = s[0];
if (c >= 'a' && c <= 'z')
hr = &mc->mc_short[c - 'a'];
else if (c >= 'A' && c <= 'Z')
hr = &mc->mc_short[c - 'A'];
else
hr = mc->mc_unknown;
if (hr->hr_class == NULL)
hr = mc->mc_unknown;
}
else {
msg_hclass_t *hc;
/* long form */
for (hr = NULL; (hc = mc->mc_hash[i].hr_class); i = (i + 1) % N) {
if (m == hc->hc_len && strncasecmp(s, hc->hc_name, m) == 0) {
hr = &mc->mc_hash[i];
break;
}
}
if (hr == NULL)
hr = mc->mc_unknown;
}
if (!return_start_of_content) /* Just header name */
return hr;
if (s[len] == ':') { /* Fast path */
*return_start_of_content = ++len;
return hr;
}
if (IS_LWS(s[len])) {
int crlf = 0;
do {
len += span_ws(s + len + crlf) + crlf; /* Skip lws before colon */
crlf = CRLF_TEST(s[len], s[len + 1]);
}
while (IS_WS(s[len + crlf]));
}
if (s[len++] != ':') /* Colon is required in header */
len = 0;
*return_start_of_content = len;
return hr;
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,70 @@
/**@ingroup msg_mime
* @IFILE msg_mime_table.c.in
*
* Template for <msg_mime_table.c>.
*
* @date Created: Wed Feb 21 11:01:45 2001 ppessi
*/
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup msg_mime
*
* @CFILE msg_mime_table.c
* @brief Parser table used for testing.
*
* #AUTO#
*
* This file is generated from template <msg_mime_table.c.in>.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*/
#include "config.h"
#include <stddef.h>
#include <string.h>
#include <sofia-sip/msg_mime.h>
#include <sofia-sip/msg_mime_protos.h>
#include <sofia-sip/msg_mclass.h>
#define msg_multipart_extract_body NULL
#define msg_request_class NULL
#define mp_request mp_common
#define msg_status_class NULL
#define mp_status mp_common
#define msg_multipart_update NULL
#define MSG_MULTIPART_HCLASS \
MSG_HEADER_CLASS(msg_, multipart, NULL, "", mp_common, append, \
msg_multipart, msg_multipart)
@@ -0,0 +1,58 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup test_msg
* @CFILE msg_name_hash.c
*
* Calculate hash for given header name.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Tue Aug 20 16:27:01 EEST 2002 ppessi
*
*/
#include "config.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <ctype.h>
#include <sofia-sip/su_alloc.h>
#include <sofia-sip/msg_mclass_hash.h>
int main(int argc, char *argv[])
{
if (!argv[1] || argv[2]) {
fprintf(stderr, "usage: msg_name_hash Header-Name\n");
exit(1);
}
printf("%d\n", msg_header_name_hash(argv[1], NULL));
exit(0);
}
@@ -0,0 +1,512 @@
#! /usr/bin/env awk
#
# This script recreates C files containing header-specific boilerplate stuff
# using the given list of headers (usually obtained from the master structure).
#
# It can also create a parser table.
#
# --------------------------------------------------------------------
#
# This file is part of the Sofia-SIP package
#
# Copyright (C) 2005 Nokia Corporation.
#
# Contact: Pekka Pessi <pekka.pessi@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
#
# --------------------------------------------------------------------
#
# Contributor(s): Pekka.Pessi@nokia.com.
#
# Created: Fri Apr 6 12:59:59 2001 ppessi
#
BEGIN {
"date '+%a %b %e %H:%M:%S %Y'" | getline date;
ascii = \
" " \
" !\"#$%&'()*+,-./0123456789:;<=>?" \
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \
"`abcdefghijklmnopqrstuvwxyz{|}~";
lower_case = "abcdefghijklmnopqrstuvwxyz";
N=0;
# Initialize these as arrays
split("", symbols);
split("", names);
split("", comments);
split("", hashes);
split("", NAMES);
split("", Comments);
split("", COMMENTS);
# indexed by the C name of the header
split("", Since); # Non-NUL if extra
split("", Extra); # Offset in extra headers
template="";
template1="";
template2="";
template3="";
prefix="";
tprefix="";
extra=0;
failed=0;
success=0;
extra_struct = "msg_pub_extra";
ERRNO="error";
}
function name_hash (name)
{
hash = 0;
len = split(name, chars, "");
for (i = 1; i <= len; i++) {
c = tolower(chars[i]);
hash = (38501 * (hash + index(ascii, c))) % 65536;
}
if (0) {
# Test that hash algorithm above agrees with the C version
pipe = ("../msg/msg_name_hash " name);
pipe | getline;
close(pipe);
if (hash != $0) {
print name ": " hash " != " $0 > "/dev/stderr";
}
}
return hash "";
}
#
# Replace magic patterns in template p with header-specific values
#
function protos (name, comment, hash, since)
{
NAME=toupper(name);
sub(/.*[\/][*][*][<][ ]*/, "", comment);
sub(/[ ]*[*][\/].*/, "", comment);
sub(/[ ]+/, " ", comment);
short = match(comment, /[(][a-z][)]/);
if (short) {
short = substr(comment, short + 1, 1);
sub(/ *[(][a-z][)]/, "", comment);
shorts[index(lower_case, short)] = name;
}
do_hash = hash == 0;
if (do_hash) {
split(comment, parts, " ");
name2 = tolower(parts[1]);
gsub(/-/, "_", name2);
if (name2 != name && name2 != tprefix "_" name) {
print name " mismatch with " comment " (" real ")" > "/dev/stderr";
}
hash = name_hash(parts[1]);
hashed[name] = hash;
if (comment !~ /header/) {
comment = comment " header";
}
}
Comment = comment;
if (!do_hash) {
comment = tolower(comment);
}
COMMENT = toupper(comment);
# Store the various forms into an array for the footer processing
N++;
hashes[N] = hash;
names[N] = name;
NAMES[N] = NAME;
comments[N] = comment;
Comments[N] = comment;
COMMENTS[N] = COMMENT;
symbols[name] = comment;
if (since) {
Since[name] = since;
Extra[name] = extra++;
}
if (PR) {
replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
}
}
function replace (p, hash, name, NAME, comment, Comment, COMMENT, since)
{
#
# Replace various forms of header name in template, print it out
#
if (p) {
gsub(/#hash#/, hash, p);
gsub(/#xxxxxx#/, name, p);
gsub(/#XXXXXX#/, NAME, p);
gsub(/#xxxxxxx_xxxxxxx#/, comment, p);
gsub(/#Xxxxxxx_Xxxxxxx#/, Comment, p);
gsub(/#XXXXXXX_XXXXXXX#/, COMMENT, p);
if (since) {
gsub(/#version#/, since, p);
}
else {
# Remove line with #version#
gsub(/\n[^\n]*#version#[^\n]*\n/, "\n", p);
}
print p > PR;
}
}
#
# Repeat each line in the footer containing the magic replacement
# pattern with a instance of all headers
#
function process_footer (text)
{
if (!match(tolower(text), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
n = length(text);
while (substr(text, n) == "\n") {
n = n - 1;
text = substr(text, 1, n);
}
if (n > 0)
print text > PR;
return;
}
n = split(text, lines, RS);
for (i = 1; i <= n; i++) {
l = lines[i];
if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
for (j = 1; j <= N; j++) {
l = lines[i];
gsub(/#hash#/, hashes[j], l);
gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
gsub(/#XXXXXXX_XXXXXXX#/, COMMENTS[j], l);
gsub(/#xxxxxx#/, names[j], l);
gsub(/#XXXXXX#/, NAMES[j], l);
print l > PR;
}
} else {
print l > PR;
}
}
}
#
# Read flags used with headers
#
function read_header_flags (flagfile, line, tokens, name, value)
{
while ((getline line < flagfile) > 0) {
sub(/^[ \t]+/, "", line);
sub(/[ \t]+$/, "", line);
if (line ~ /^#/ || line ~ /^$/)
continue;
split(line, tokens, /[ \t]*=[ \t]*/);
name = tolower(tokens[1]);
gsub(/-/, "_", name);
gsub(/,/, " ", name);
# print "FLAG: " name " = " tokens[2]
if (header_flags[name]) {
print flagfile ": already defined " tokens[1];
}
else if (!symbols[name]) {
print flagfile ": unknown header \"" tokens[1] "\"";
}
else {
header_flags[name] = tokens[2];
}
}
close(flagfile);
}
#
# Read in templates
#
function templates ()
{
if (!auto) {
auto = FILENAME;
if (!prefix) { prefix = module; }
if (!tprefix) { tprefix = prefix; }
sub(/.*\//, "", auto);
auto = "This file is automatically generated from <" auto "> by msg_parser.awk.";
if (PR) {
if (TEMPLATE == "") { TEMPLATE = PR ".in"; }
RS0=RS; RS="\f\n";
if ((getline theader < TEMPLATE) < 0) {
print ( TEMPLATE ": " ERRNO );
failed=1;
exit(1);
}
getline header < TEMPLATE;
getline template < TEMPLATE;
getline footer < TEMPLATE;
if (TEMPLATE1) {
if ((getline dummy < TEMPLATE1) < 0) {
print(TEMPLATE1 ": " ERRNO);
failed=1;
exit(1);
}
getline dummy < TEMPLATE1;
getline template1 < TEMPLATE1;
getline dummy < TEMPLATE1;
}
if (TEMPLATE2) {
if ((getline dummy < TEMPLATE2) < 0) {
print( TEMPLATE2 ": " ERRNO );
failed=1;
exit(1);
}
getline dummy < TEMPLATE2;
getline template2 < TEMPLATE2;
getline dummy < TEMPLATE2;
}
if (TEMPLATE3) {
if ((getline dummy < TEMPLATE3) < 0) {
print( TEMPLATE3 ": " ERRNO );
failed=1;
exit(1);
}
getline dummy < TEMPLATE3;
getline template3 < TEMPLATE3;
getline dummy < TEMPLATE3;
}
sub(/.*[\/]/, "", TEMPLATE);
gsub(/#AUTO#/, auto, header);
gsub(/#DATE#/, "@date Generated: " date, header);
if (PACKAGE_NAME) gsub(/#PACKAGE_NAME#/, PACKAGE_NAME, header);
if (PACKAGE_VERSION) gsub(/#PACKAGE_VERSION#/, PACKAGE_VERSION, header);
print header > PR;
RS=RS0;
}
if (!NO_FIRST) {
protos("request", "/**< Request line */", -1);
protos("status", "/**< Status line */", -2);
}
}
}
/^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
HLIST && /^[a-z]/ { protos($1, $0, 0, $2); headers[total++] = $1; }
/^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; }
/^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); }
/^ *\/\* === Headers end here \*\// { in_header_list=0; }
PT && /^ *\/\* === Hash headers end here \*\// { in_header_list=0;}
in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ {
n=$0
sub(/;.*$/, "", n);
sub(/^ *(sip|rtsp|http|msg|mp)_[a-z0-9_]*_t[ ]*/, "", n);
sub(/^[*](sip|rtsp|http|msg|mp)_/, "", n);
if ($0 !~ /[\/][*][*][<]/) {
getline;
}
if ($0 !~ /[\/][*][*][<]/) {
printf "msg_protos.awk: header %s is malformed\n", n;
failed=1;
exit 1;
}
if (!NO_MIDDLE)
protos(n, $0, 0);
headers[total++] = n;
}
END {
if (failed) { exit };
if (!NO_LAST) {
protos("unknown", "/**< Unknown headers */", -3);
protos("error", "/**< Erroneous headers */", -4);
protos("separator", "/**< Separator line between headers and payload */", -5);
protos("payload", "/**< Message payload */", -6);
if (multipart)
protos("multipart", "/**< Multipart payload */", -7);
}
if (PR) {
process_footer(footer);
}
else if (PT) {
if (FLAGFILE)
read_header_flags(FLAGFILE);
if (TEMPLATE == "") { TEMPLATE = PT ".in"; }
RS0=RS; RS=" \n";
getline theader < TEMPLATE;
getline header < TEMPLATE;
getline template < TEMPLATE;
getline footer < TEMPLATE;
RS=RS0;
module_struct = module "_t";
sub(/.*[\/]/, "", TEMPLATE);
gsub(/#AUTO#/, auto, header);
gsub(/#DATE#/, "@date Generated: " date, header);
print header > PT;
if (MC_SHORT_SIZE) {
printf("static msg_href_t const " \
"%s_short_forms[MC_SHORT_SIZE] = \n{\n",
module) > PT;
for (i = 1; i <= MC_SHORT_SIZE; i = i + 1) {
c = (i == MC_SHORT_SIZE) ? "" : ",";
if (i in shorts) {
n = shorts[i];
flags = header_flags[n]; if (flags) flags = ",\n " flags;
printf(" { /* %s */ %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
substr(lower_case, i, 1),
tprefix, n, module, prefix, n, flags, c) \
> PT;
}
else {
printf(" { NULL }%s\n", c) \
> PT;
}
}
printf("};\n\n") > PT;
}
# printf("extern msg_hclass_t msg_multipart_class[];\n\n") > PT;
if (extra > 0) {
printf("struct %s {\n", extra_struct) > PT;
printf(" %s base;\n", module_struct) > PT;
printf(" msg_header_t *extra[%u];\n", extra) > PT;
printf("};\n\n") > PT;
module_struct = "struct " extra_struct;
}
printf("msg_mclass_t const %s_mclass[1] = \n{{\n", module) > PT;
printf("# if defined (%s_HCLASS)\n", toupper(module)) > PT;
printf(" %s_HCLASS,\n", toupper(module)) > PT;
printf("#else\n") > PT;
printf(" {{ 0 }},\n") > PT;
printf("#endif\n") > PT;
printf(" %s_VERSION_CURRENT,\n", toupper(module)) > PT;
printf(" %s_PROTOCOL_TAG,\n", toupper(module)) > PT;
printf("#if defined (%s_PARSER_FLAGS)\n", toupper(module)) > PT;
printf(" %s_PARSER_FLAGS,\n", toupper(module)) > PT;
printf("#else\n") > PT;
printf(" 0,\n") > PT;
printf("#endif\n") > PT;
printf(" sizeof (%s),\n", module_struct) > PT;
printf(" %s_extract_body,\n", module) > PT;
len = split("request status separator payload unknown error", unnamed, " ");
for (i = 1; i <= len; i++) {
printf(" {{ %s_%s_class, offsetof(%s_t, %s_%s) }},\n",
tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
}
if (multipart) {
printf(" {{ %s_class, offsetof(%s_t, %s_multipart) }},\n",
multipart, module, prefix) > PT;
} else {
printf(" {{ NULL, 0 }},\n") > PT;
}
if (MC_SHORT_SIZE) {
printf(" %s_short_forms, \n", module) > PT;
}
else {
printf(" NULL, \n") > PT;
}
printf(" %d, %d, \n", MC_HASH_SIZE, total) > PT;
printf(" {\n") > PT;
for (i = 0; i < total; i++) {
n = headers[i];
h = hashed[n];
if (h < 0)
continue;
j = h % MC_HASH_SIZE; if (j == -0) j = 0;
for (; j in header_hash;) {
if (++j == MC_HASH_SIZE) {
j = 0;
}
}
header_hash[j] = n;
}
for (i = 0; i < MC_HASH_SIZE; i++) {
c = (i + 1 == MC_HASH_SIZE) ? "" : ",";
if (i in header_hash) {
n = header_hash[i];
flags = header_flags[n]; if (flags) flags = ",\n " flags;
if (Since[n]) {
printf(" { %s_%s_class, offsetof(struct %s, extra[%u])%s }%s\n",
tprefix, n, extra_struct, Extra[n], flags, c) > PT;
}
else {
printf(" { %s_%s_class, offsetof(%s_t, %s_%s)%s }%s\n",
tprefix, n, module, prefix, n, flags, c) > PT;
}
}
else {
printf(" { NULL, 0 }%s\n", c) > PT;
}
}
printf(" }\n}};\n\n") > PT;
}
exit success;
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,371 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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 msg_tag.c Message tag classes
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Feb 23 12:46:42 2001 ppessi
*
*/
#include "config.h"
#include <assert.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <sofia-sip/su.h>
#define TAG_NAMESPACE "msg"
#include "msg_internal.h"
#include "sofia-sip/msg_header.h"
#include "sofia-sip/msg_parser.h"
#include <sofia-sip/su_tag_class.h>
#include <sofia-sip/su_tag_inline.h>
#include <sofia-sip/su_tagarg.h>
#include "sofia-sip/msg_tag_class.h"
#define NONE ((void*)-1)
int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size)
{
msg_header_t const *h;
assert(t);
if (!t) {
if (size) b[0] = 0;
return 0;
}
h = (msg_header_t const *)t->t_value;
if (h != MSG_HEADER_NONE && h != NULL) {
return msg_header_field_e(b, size, h, 0);
}
else {
return snprintf(b, size, "<NONE>");
}
}
size_t msghdrtag_xtra(tagi_t const *t, size_t offset)
{
msg_header_t const *h;
size_t rv;
msg_hclass_t *hc = (msg_hclass_t *)t->t_tag->tt_magic;
assert(t);
for (h = (msg_header_t const *)t->t_value, rv = offset;
h != NULL;
h = h->sh_next) {
if (h == MSG_HEADER_NONE)
break;
MSG_STRUCT_SIZE_ALIGN(rv);
if (hc)
rv = hc->hc_dxtra(h, rv + h->sh_class->hc_size);
else
rv = h->sh_class->hc_dxtra(h, rv + h->sh_class->hc_size);
}
return rv - offset;
}
tagi_t *msghdrtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
{
msg_header_t const *o;
msg_header_t *h, *h0 = NULL, **hh;
msg_hclass_t *hc, *hc0 = (msg_hclass_t *)src->t_tag->tt_magic;
char *b;
size_t size;
assert(src); assert(*bb);
dst->t_tag = src->t_tag;
dst->t_value = 0L;
b = *bb;
hh = &h0;
for (o = (msg_header_t const *)src->t_value;
o != NULL;
o = o->sh_next) {
if (o == MSG_HEADER_NONE) {
*hh = (msg_header_t *)o;
break;
}
/* XXX assert(msg_hdr_p(o)); */
MSG_STRUCT_ALIGN(b);
h = (msg_header_t *)b;
hc = hc0 ? hc0 : o->sh_class;
b += hc->hc_size;
memset(h, 0, hc->hc_size);
h->sh_class = hc;
size = SIZE_MAX - (uintptr_t)b;
if (size > ISSIZE_MAX)
size = ISSIZE_MAX;
b = hc->hc_dup_one(h, o, b, size);
if (hc->hc_update)
msg_header_update_params(h->sh_common, 0);
*hh = h; hh = &h->sh_next;
assert(b != NULL);
}
*bb = b;
dst->t_value = (tag_value_t)h0;
return dst + 1;
}
/** Convert a string to a header structure based on to the tag. */
int msghdrtag_scan(tag_type_t tt, su_home_t *home,
char const *s,
tag_value_t *return_value)
{
msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
msg_header_t *h;
int retval;
h = msg_header_make(home, hc, s);
if (h)
*return_value = (tag_value_t)h, retval = 1;
else
*return_value = (tag_value_t)NULL, retval = -1;
return retval;
}
tagi_t *msgstrtag_filter(tagi_t *dst,
tagi_t const f[],
tagi_t const *src,
void **bb);
int msgobjtag_snprintf(tagi_t const *t, char b[], size_t size)
{
msg_pub_t const *mo;
assert(t);
if (!t || !t->t_value) {
if (size) b[0] = 0;
return 0;
}
mo = (msg_pub_t *)t->t_value;
return (int)msg_object_e(b, size, mo, MSG_DO_CANONIC);
}
size_t msgobjtag_xtra(tagi_t const *t, size_t offset)
{
msg_header_t const *h;
msg_pub_t const *mo;
size_t rv;
assert(t);
mo = (msg_pub_t const *)t->t_value;
if (mo == NULL || mo == NONE)
return 0;
rv = offset;
MSG_STRUCT_SIZE_ALIGN(rv);
rv += mo->msg_size;
if (mo->msg_request)
h = (msg_header_t const *)mo->msg_request;
else
h = (msg_header_t const *)mo->msg_status;
for (; h; h = h->sh_succ) {
MSG_STRUCT_SIZE_ALIGN(rv);
rv += msg_header_size(h);
}
return rv - offset;
}
tagi_t *msgobjtag_dup(tagi_t *dst, tagi_t const *src, void **bb)
{
msg_pub_t const *omo;
msg_pub_t *mo;
msg_header_t *h;
msg_header_t const *o;
char *b;
assert(src); assert(*bb);
omo = (msg_pub_t const *)src->t_value;
dst->t_tag = src->t_tag;
dst->t_value = 0;
if (omo == NULL || omo == NONE) {
dst->t_value = src->t_value;
return dst + 1;
}
b = *bb;
MSG_STRUCT_ALIGN(b);
mo = (msg_pub_t *)b;
b += omo->msg_size;
memset(mo, 0, omo->msg_size);
mo->msg_size = omo->msg_size;
mo->msg_flags = omo->msg_flags;
if (mo->msg_request)
o = mo->msg_request;
else
o = mo->msg_status;
for (; o; o = o->sh_succ) {
size_t size;
MSG_STRUCT_ALIGN(b);
h = (msg_header_t *)b;
b += o->sh_class->hc_size;
memset(h, 0, o->sh_class->hc_size);
h->sh_class = o->sh_class;
size = SIZE_MAX - (uintptr_t)b;
if (size > ISSIZE_MAX)
size = ISSIZE_MAX;
b = o->sh_class->hc_dup_one(h, o, b, size);
if (o->sh_class->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(b != NULL);
}
dst->t_value = (tag_value_t)mo;
*bb = b;
return dst + 1;
}
#if 0
int msgtag_multipart_xtra(tagi_t const *t, int offset)
{
msg_header_t const *h;
msg_multipart_t const *mp;
int rv;
assert(t);
mp = (msg_multipart_t const *)t->t_value;
if (mp == NULL || mp == NONE)
return 0;
rv = offset;
MSG_STRUCT_SIZE_ALIGN(rv);
rv += mo->msg_size;
if (mo->msg_request)
h = (msg_header_t const *)mo->msg_request;
else
h = (msg_header_t const *)mo->msg_status;
for (; h; h = h->sh_succ) {
MSG_STRUCT_SIZE_ALIGN(rv);
rv += msg_header_size(h);
}
return rv - offset;
}
tagi_t *msgtag_multipart_dup(tagi_t *dst, tagi_t const *src, void **bb)
{
msg_pub_t const *omo;
msg_pub_t *mo;
msg_header_t *h;
msg_header_t const *o;
char *b;
assert(src); assert(*bb);
omo = (msg_pub_t const *)src->t_value;
dst->t_tag = src->t_tag;
dst->t_value = 0;
if (omo == NULL || omo == NONE) {
dst->t_value = src->t_value;
return dst + 1;
}
b = *bb;
MSG_STRUCT_ALIGN(b);
mo = (msg_pub_t *)b;
b += omo->msg_size;
memset(mo, 0, omo->msg_size);
mo->msg_size = omo->msg_size;
mo->msg_flags = omo->msg_flags;
if (mo->msg_request)
o = mo->msg_request;
else
o = mo->msg_status;
for (; o; o = o->sh_succ) {
size_t size;
MSG_STRUCT_ALIGN(b);
h = (msg_header_t *)b;
b += o->sh_class->hc_size;
memset(h, 0, o->sh_class->hc_size);
h->sh_class = o->sh_class;
size = SIZE_MAX - (uintptr_t)b;
if (size > ISSIZE_MAX)
size = ISSIZE_MAX;
b = o->sh_class->hc_dup_one(h, o, b, size);
if (o->sh_class->hc_update)
msg_header_update_params(h->sh_common, 0);
assert(b != NULL);
}
dst->t_value = (long)mo;
*bb = b;
return dst + 1;
}
#endif
@@ -0,0 +1,173 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_H
/** Defined when <sofia-sip/msg.h> has been included */
#define MSG_H
/**@file sofia-sip/msg.h
*
* Base message interface.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Feb 18 08:54:48 2000 ppessi
*/
#include <sofia-sip/msg_types.h>
#include <sofia-sip/su_alloc.h>
SOFIA_BEGIN_DECLS
SOFIAPUBFUN msg_t *msg_create(msg_mclass_t const *mc, int flags);
SOFIAPUBFUN void msg_destroy(msg_t *);
SOFIAPUBFUN msg_t *msg_copy(msg_t *);
SOFIAPUBFUN msg_t *msg_dup(msg_t const *);
SOFIAPUBFUN msg_t *msg_make(msg_mclass_t const *mc, int flags,
void const *data, ssize_t len);
SOFIAPUBFUN char *msg_as_string(su_home_t *home,
msg_t *msg, msg_pub_t *pub, int flags,
size_t *return_len);
SOFIAPUBFUN void msg_set_parent(msg_t *kid, msg_t *dad);
SOFIAPUBFUN msg_t *msg_ref_create(msg_t *);
SOFIAPUBFUN void msg_ref_destroy(msg_t *);
SOFIAPUBFUN msg_pub_t *msg_public(msg_t const *msg, void *tag);
SOFIAPUBFUN msg_pub_t *msg_object(msg_t const *msg);
SOFIAPUBFUN msg_mclass_t const *msg_mclass(msg_t const *msg);
SOFIAPUBFUN int msg_extract(msg_t *msg);
SOFIAPUBFUN unsigned msg_extract_errors(msg_t const *msg);
SOFIAPUBFUN int msg_is_complete(msg_t const *msg);
SOFIAPUBFUN int msg_has_error(msg_t const *msg);
SOFIAPUBFUN msg_header_t **msg_chain_head(msg_t const *msg);
SOFIAPUBFUN int msg_serialize(msg_t *msg, msg_pub_t *mo);
SOFIAPUBFUN int msg_prepare(msg_t *msg);
SOFIAPUBFUN void msg_unprepare(msg_t *msg);
SOFIAPUBFUN int msg_is_prepared(msg_t const *msg);
SOFIAPUBFUN usize_t msg_size(msg_t const *msg);
SOFIAPUBFUN usize_t msg_maxsize(msg_t *msg, usize_t maxsize);
/** Cast a #msg_t pointer to a #su_home_t pointer. */
#define msg_home(h) ((su_home_t*)(h))
/** Streaming state of a #msg_t object. */
enum msg_streaming_status {
/** Disable streaming */
msg_stop_streaming = 0,
/** Enable streaming */
msg_start_streaming = 1
};
SOFIAPUBFUN int msg_is_streaming(msg_t const *msg);
SOFIAPUBFUN void msg_set_streaming(msg_t *msg, enum msg_streaming_status what);
SOFIAPUBFUN unsigned msg_mark_as_complete(msg_t *msg, unsigned mask);
SOFIAPUBFUN unsigned msg_get_flags(msg_t const *msg, unsigned mask);
SOFIAPUBFUN unsigned msg_set_flags(msg_t *msg, unsigned mask);
SOFIAPUBFUN unsigned msg_zap_flags(msg_t *msg, unsigned mask);
/** Flags controlling parser/printer. */
enum msg_flg_user {
/** Use compact form when printing. */
MSG_FLG_COMPACT = (1<<0),
/** Use canonic representation when printing. */
MSG_FLG_CANONIC = (1<<1),
/** Cache a copy of headers when parsing. */
MSG_FLG_EXTRACT_COPY = (1<<2),
/** Print comma-separated lists instead of separate headers */
MSG_FLG_COMMA_LISTS = (1<<3),
/**Use mailbox format when parsing - in mailbox format
* message has no body unless Content-Length header is present.
*/
MSG_FLG_MAILBOX = (1<<4),
/** Use multiple parts for message body */
MSG_FLG_CHUNKING = (1<<5),
/** Enable streaming - parser gives completed message fragments when they
* are ready to upper layers */
MSG_FLG_STREAMING = (1<<6),
/** Make messages threadsafe. */
MSG_FLG_THRDSAFE = (1<<15),
MSG_FLG_USERMASK = (1<<16) - 1
};
/** Flags used by parser. */
enum msg_flg_parser {
/** Extract headers for this message */
MSG_FLG_HEADERS = (1<<16),
/** Extract body for this message */
MSG_FLG_BODY = (1<<17),
/** Extract chunks for this message */
MSG_FLG_CHUNKS = (1<<18),
/** Extract trailers for this message */
MSG_FLG_TRAILERS = (1<<19),
/** Extract last component of this message */
MSG_FLG_FRAGS = (1<<20),
/** This message has been completely extracted */
MSG_FLG_COMPLETE = (1<<24),
/** This message has parsing errors */
MSG_FLG_ERROR = (1<<25),
/** This message is too large */
MSG_FLG_TOOLARGE = (1<<26),
/** This message is truncated */
MSG_FLG_TRUNC = (1<<27),
/** This message has timeout */
MSG_FLG_TIMEOUT = (1<<28),
MSG_FLG_PARSERMASK = ((-1) ^ ((1<<16) - 1))
};
#define MSG_DO_COMPACT MSG_FLG_COMPACT
#define MSG_DO_CANONIC MSG_FLG_CANONIC
#define MSG_DO_EXTRACT_COPY MSG_FLG_EXTRACT_COPY
/** Test if all the flags in @a v are set in @a f. */
#define MSG_FLAGS(f, v) (((f) & (v)) == v)
#define MSG_IS_COMPACT(f) MSG_FLAGS((f), MSG_FLG_COMPACT)
#define MSG_IS_CANONIC(f) MSG_FLAGS((f), MSG_FLG_CANONIC)
#define MSG_IS_EXTRACT_COPY(f) MSG_FLAGS((f), MSG_FLG_EXTRACT_COPY)
#define MSG_IS_COMMA_LISTS(f) MSG_FLAGS((f), MSG_FLG_COMMA_LISTS)
#define MSG_IS_MAILBOX(f) MSG_FLAGS((f), MSG_FLG_MAILBOX)
#define MSG_HAS_COMPLETE(f) MSG_FLAGS((f), MSG_FLG_COMPLETE)
#define MSG_HAS_ERROR(f) MSG_FLAGS((f), MSG_FLG_ERROR)
#define MSG_IS_COMPLETE(mo) (((mo)->msg_flags & MSG_FLG_COMPLETE) != 0)
SOFIA_END_DECLS
#endif /* MSG_H */
@@ -0,0 +1,97 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_ADDR_H
/** Defined when <sofia-sip/msg_addr.h> has been included. */
#define MSG_ADDR_H
/**@file sofia-sip/msg_addr.h
* @brief Addressing and I/O interface for messages.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jun 8 19:28:55 2000 ppessi
*/
#ifndef MSG_H
#include <sofia-sip/msg.h>
#endif
#ifndef SU_H
#include <sofia-sip/su.h>
#endif
SOFIA_BEGIN_DECLS
SOFIAPUBFUN void msg_addr_zero(msg_t *msg);
SOFIAPUBFUN su_addrinfo_t *msg_addrinfo(msg_t *msg);
SOFIAPUBFUN su_sockaddr_t *msg_addr(msg_t *msg);
SOFIAPUBFUN int msg_get_address(msg_t *msg, su_sockaddr_t *, socklen_t *);
SOFIAPUBFUN int msg_set_address(msg_t *msg, su_sockaddr_t const *, socklen_t);
SOFIAPUBFUN void msg_addr_copy(msg_t *dst, msg_t const *src);
SOFIAPUBFUN int msg_errno(msg_t const *msg);
SOFIAPUBFUN void msg_set_errno(msg_t *msg, int err);
enum {
/** Minimum size of a message buffer */
msg_min_size = 512,
/** Minimum size of external buffer */
msg_min_block = 8192,
/** Number of external buffers */
msg_n_fragments = 8
};
/** I/O vector type.
* @sa msg_recv_iovec(), msg_iovec(), #su_iovec_s, su_vsend(), su_vrecv().
*/
typedef struct su_iovec_s msg_iovec_t;
#define mv_base siv_base
#define mv_len siv_len
SOFIAPUBFUN isize_t msg_iovec(msg_t *msg, msg_iovec_t vec[], isize_t veclen);
SOFIAPUBFUN issize_t msg_recv_iovec(msg_t *msg,
msg_iovec_t vec[], isize_t veclen, usize_t n,
int exact);
SOFIAPUBFUN isize_t msg_recv_commit(msg_t *msg, usize_t n, int eos);
SOFIAPUBFUN issize_t msg_recv_buffer(msg_t *msg, void **return_buffer);
SOFIAPUBFUN msg_t *msg_next(msg_t *msg);
SOFIAPUBFUN int msg_set_next(msg_t *msg, msg_t *next);
SOFIAPUBFUN void msg_clear_committed(msg_t *msg);
SOFIAPUBFUN issize_t msg_buf_external(msg_t *msg,
usize_t N,
usize_t blocksize);
SOFIA_END_DECLS
#endif /* !defined(MSG_ADDR_H) */
@@ -0,0 +1,57 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_BUFFER_H
/** Defined when <sofia-sip/msg_buffer.h> has been included. */
#define MSG_BUFFER_H
/**@file sofia-sip/msg_buffer.h
* @brief Internal buffer management functions.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Nov 8 12:23:00 2002 ppessi
*
*/
#ifndef MSG_TYPES_H
#include <sofia-sip/msg_types.h>
#endif
SOFIA_BEGIN_DECLS
SOFIAPUBFUN void *msg_buf_alloc(msg_t *msg, usize_t size);
SOFIAPUBFUN void *msg_buf_exact(msg_t *msg, usize_t size);
SOFIAPUBFUN usize_t msg_buf_commit(msg_t *msg, usize_t size, int eos);
SOFIAPUBFUN usize_t msg_buf_committed(msg_t const *msg);
SOFIAPUBFUN void *msg_buf_committed_data(msg_t const *msg);
SOFIAPUBFUN usize_t msg_buf_size(msg_t const *msg);
SOFIAPUBFUN void *msg_buf_move(msg_t *dst, msg_t const *src);
SOFIAPUBFUN void msg_buf_set(msg_t *msg, void *b, usize_t size);
SOFIA_END_DECLS
#endif /* !defined MSG_BUFFER_H */
@@ -0,0 +1,76 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_DATE_H
/** Defined when <sofia-sip/msg_date.h> has been included. */
#define MSG_DATE_H
/**@ingroup msg_parser
* @file sofia-sip/msg_date.h
* @brief Types and functions for handling dates and times.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jun 8 19:28:55 2000 ppessi
*
*/
#ifndef SU_TYPES_H
#include <sofia-sip/su_types.h>
#endif
SOFIA_BEGIN_DECLS
#ifndef MSG_TIME_T_DEFINED
#define MSG_TIME_T_DEFINED
/** Time in seconds since epoch (1900-Jan-01 00:00:00). */
typedef unsigned long msg_time_t;
#endif
#ifndef MSG_TIME_MAX
/** Latest time that can be expressed with msg_time_t. @HIDE */
#define MSG_TIME_MAX ((msg_time_t)ULONG_MAX)
#endif
/* Current time. */
SOFIAPUBFUN msg_time_t msg_now(void);
SOFIAPUBFUN issize_t msg_date_delta_d(char const **inout_string,
msg_time_t *return_date,
msg_time_t *return_delta);
SOFIAPUBFUN issize_t msg_delta_d(char const **ss, msg_time_t *return_delta);
SOFIAPUBFUN issize_t msg_delta_e(char b[], isize_t bsiz, msg_time_t delta);
/** Decode RFC1123-date, RFC822-date or asctime-date. */
SOFIAPUBFUN issize_t msg_date_d(char const **ss, msg_time_t *date);
/** Encode RFC1123-date. */
SOFIAPUBFUN issize_t msg_date_e(char b[], isize_t bsiz, msg_time_t date);
enum { msg_date_string_size = 29 };
SOFIA_END_DECLS
#endif /* !defined(MSG_DATE_H) */
@@ -0,0 +1,304 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_HEADER_H
/** Defined when <sofia-sip/msg_header.h> has been included. */
#define MSG_HEADER_H
/**@ingroup msg_headers
* @file sofia-sip/msg_header.h
*
* @brief Message headers.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Mon Aug 27 15:44:27 2001 ppessi
*
*/
#include <stdarg.h>
#include <string.h>
#ifndef SU_TYPES_H
#include <sofia-sip/su_types.h>
#endif
#ifndef SU_ALLOC_H
#include <sofia-sip/su_alloc.h>
#endif
#ifndef MSG_H
#include <sofia-sip/msg.h>
#endif
#ifndef URL_H
#include <sofia-sip/url.h>
#endif
SOFIA_BEGIN_DECLS
SOFIAPUBFUN msg_header_t *msg_header_alloc(su_home_t *,
msg_hclass_t *hc,
isize_t extra)
__attribute__((__malloc__));
SOFIAPUBFUN isize_t msg_header_size(msg_header_t const *h);
SOFIAPUBFUN msg_header_t **msg_header_offset(msg_t const *,
msg_pub_t const *,
msg_header_t const *);
SOFIAPUBFUN msg_header_t **msg_hclass_offset(msg_mclass_t const *,
msg_pub_t const *,
msg_hclass_t *);
SOFIAPUBFUN msg_header_t *msg_header_access(msg_pub_t const *pub,
msg_hclass_t *hc);
SOFIAPUBFUN msg_header_t *msg_header_copy_as(su_home_t *home,
msg_hclass_t *hc,
msg_header_t const *o)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_copy(su_home_t *home,
msg_header_t const *o)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_copy_one(su_home_t *home,
msg_header_t const *o)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_dup_as(su_home_t *home,
msg_hclass_t *hc,
msg_header_t const *o)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_dup(su_home_t *home,
msg_header_t const *h)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_dup_one(su_home_t *home,
msg_header_t const *h)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_d(su_home_t *home,
msg_t const *msg,
char const *b);
SOFIAPUBFUN issize_t msg_header_e(char b[], isize_t bsiz,
msg_header_t const *h,
int flags);
SOFIAPUBFUN issize_t msg_object_e(char b[], isize_t size,
msg_pub_t const *mo,
int flags);
SOFIAPUBFUN issize_t msg_header_field_e(char b[], isize_t bsiz,
msg_header_t const *h,
int flags);
SOFIAPUBFUN int msg_header_remove(msg_t *msg,
msg_pub_t *mo,
msg_header_t *h);
SOFIAPUBFUN int msg_header_remove_all(msg_t *msg,
msg_pub_t *mo,
msg_header_t *h);
SOFIAPUBFUN int msg_header_insert(msg_t *msg, msg_pub_t *mo,
msg_header_t *h);
SOFIAPUBFUN int msg_header_replace(msg_t *msg, msg_pub_t *mo,
msg_header_t *old_header,
msg_header_t *new_header);
SOFIAPUBFUN int msg_header_add_dup(msg_t *msg,
msg_pub_t *pub,
msg_header_t const *o);
SOFIAPUBFUN int msg_header_add_str(msg_t *msg,
msg_pub_t *pub,
char const *str);
SOFIAPUBFUN int msg_header_parse_str(msg_t *msg,
msg_pub_t *pub,
char *s);
SOFIAPUBFUN int msg_header_add_dup_as(msg_t *msg,
msg_pub_t *pub,
msg_hclass_t *hc,
msg_header_t const *o);
SOFIAPUBFUN int msg_header_add_make(msg_t *msg,
msg_pub_t *pub,
msg_hclass_t *hc,
char const *s);
SOFIAPUBFUN int msg_header_prepend(msg_t *msg,
msg_pub_t *pub,
msg_header_t **hh,
msg_header_t *h);
SOFIAPUBFUN msg_header_t *msg_header_make(su_home_t *home,
msg_hclass_t *hc,
char const *s)
__attribute__((__malloc__));
SOFIAPUBFUN msg_header_t *msg_header_format(su_home_t *home,
msg_hclass_t *hc,
char const *fmt, ...)
__attribute__ ((__malloc__, __format__ (printf, 3, 4)));
SOFIAPUBFUN msg_header_t *msg_header_vformat(su_home_t *home,
msg_hclass_t *hc,
char const *fmt,
va_list ap)
__attribute__((__malloc__));
SOFIAPUBFUN void msg_header_free(su_home_t *home,
msg_header_t *h);
SOFIAPUBFUN void msg_header_free_all(su_home_t *home,
msg_header_t *h);
SOFIAPUBFUN msg_payload_t *msg_payload_create(su_home_t *home,
void const *data,
usize_t len)
__attribute__((__malloc__));
SOFIAPUBFUN msg_separator_t *msg_separator_create(su_home_t *home)
__attribute__((__malloc__));
/* Chunk handling macros */
/** Get pointer to beginning of available buffer space */
#define MSG_CHUNK_BUFFER(pl) \
((char *)pl->pl_common->h_data + (pl)->pl_common->h_len)
/** Get size of available buffer space */
#define MSG_CHUNK_AVAIL(pl) \
((pl)->pl_len + ((pl)->pl_data - (char *)pl->pl_common->h_data) - \
(pl)->pl_common->h_len)
/** Get next chunk in list */
#define MSG_CHUNK_NEXT(pl) \
((pl)->pl_next)
SOFIAPUBFUN issize_t msg_headers_prepare(msg_t *,
msg_header_t *headers,
int flags);
#ifdef SU_HAVE_INLINE
/** Clear encoded data from header structure. */
static inline void msg_fragment_clear(msg_common_t *h)
{
h->h_data = NULL, h->h_len = 0;
}
/** Pointer to header parameters. */
static inline
msg_param_t **msg_header_params(msg_common_t const *h)
{
if (h && h->h_class->hc_params) {
return (msg_param_t **)((char *)h + h->h_class->hc_params);
}
return NULL;
}
#else
#define msg_fragment_clear(h) ((h)->h_data = NULL, (h)->h_len = 0)
#define msg_header_params(h) \
(((h) && ((msg_common_t *)h)->h_class->hc_params) ? \
(msg_param_t **)((char *)(h) + ((msg_common_t *)h)->h_class->hc_params) : NULL)
#endif
SOFIAPUBFUN char const *msg_header_find_param(msg_common_t const *,
char const *name);
SOFIAPUBFUN int msg_header_add_param(su_home_t *, msg_common_t *h,
char const *param);
SOFIAPUBFUN int msg_header_replace_param(su_home_t *, msg_common_t *h,
char const *param);
SOFIAPUBFUN int msg_header_remove_param(msg_common_t *h, char const *name);
SOFIAPUBFUN char const *msg_header_find_item(msg_common_t const *h,
char const *item);
SOFIAPUBFUN int msg_header_replace_item(su_home_t *, msg_common_t *h,
char const *item);
SOFIAPUBFUN int msg_header_remove_item(msg_common_t *h, char const *name);
/** Append a list of constant items to a list. */
SOFIAPUBFUN int msg_list_append_items(su_home_t *home,
msg_list_t *k,
msg_param_t const items[]);
/** Replace a list of constant items on a list */
SOFIAPUBFUN int msg_list_replace_items(su_home_t *home,
msg_list_t *k,
msg_param_t const items[]);
SOFIAPUBFUN int msg_header_join_items(su_home_t *home,
msg_common_t *dst,
msg_common_t const *src,
int duplicate);
SOFIAPUBFUN issize_t msg_random_token(char token[], isize_t tlen,
void const *d, isize_t dlen);
SOFIAPUBFUN msg_param_t msg_params_find(msg_param_t const pp[],
char const *name);
SOFIAPUBFUN msg_param_t *msg_params_find_slot(msg_param_t [],
char const *name);
SOFIAPUBFUN int msg_params_add(su_home_t *sh,
msg_param_t **pp,
char const *param);
SOFIAPUBFUN int msg_params_cmp(char const * const a[],
char const * const b[]);
SOFIAPUBFUN int msg_params_replace(su_home_t *,
char const * **inout_paramlist,
char const *);
SOFIAPUBFUN int msg_params_remove(char const **paramlist,
char const *name);
SOFIAPUBFUN size_t msg_params_length(char const * const * params);
/** Unquote a string, return a duplicate. */
SOFIAPUBFUN char *msg_unquote_dup(su_home_t *home, char const *q)
__attribute__((__malloc__));
SOFIAPUBFUN char *msg_unquote(char *dst, char const *s);
/** Calculate a hash over a string. */
SOFIAPUBFUN unsigned long msg_hash_string(char const *id);
/* Align pointer p for multiple of t (which must be a power of 2) */
#define MSG_ALIGN(p, t) (((uintptr_t)(p) + (t) - 1) & (0 - (uintptr_t)(t)))
#define MSG_STRUCT_SIZE_ALIGN(rv) ((rv) = MSG_ALIGN(rv, sizeof(void *)))
#define MSG_STRUCT_ALIGN(p) ((p) = (void*)MSG_ALIGN(p, sizeof(void *)))
enum {
msg_n_params = 8, /* allocation size of parameter string list */
#define MSG_N_PARAMS msg_n_params
};
/** Initialize a header structure. @HIDE */
#define MSG_HEADER_INIT(h, msg_class, size) \
((void)memset((h), 0, (size)), \
(void)(((msg_common_t *)(h))->h_class = (msg_class)), \
(h))
/** No header. */
#define MSG_HEADER_NONE ((msg_header_t *)-1)
SOFIA_END_DECLS
#ifndef MSG_PROTOS_H
#include <sofia-sip/msg_protos.h>
#endif
#endif /** !defined(MSG_HEADER_H) */
@@ -0,0 +1,148 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_MCLASS_H
/** Defined when <sofia-sip/msg_mclass.h> has been included. */
#define MSG_MCLASS_H
/**@ingroup msg_parser
* @file sofia-sip/msg_mclass.h
*
* @brief Parser table and message factory object.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Mon Aug 27 15:44:27 2001 ppessi
*/
#ifndef MSG_HEADER_H
#include <sofia-sip/msg_header.h>
#endif
SOFIA_BEGIN_DECLS
enum {
/** Default size of hash table */
MC_HASH_SIZE = 127,
/** Size of short form table */
MC_SHORT_SIZE = 'Z' - 'A' + 1
};
/**Header reference.
*
* A header reference object contains a pointer to a
* @ref msg_hclass_s "header class"
* and a offset to the header objects within the @ref msg_pub_t "public
* message structure".
*
* The @a hr_flags field is used to provide classification of headers. For
* instance, the msg_extract_errors() returns bitwise or of all hr_flags
* belonging to headers with parsing errors.
*/
struct msg_href_s
{
msg_hclass_t *hr_class; /**< Header class */
unsigned short hr_offset; /**< Offset within public message struct. */
unsigned short hr_flags; /**< Header flags */
};
/**Factory object for protocol messages.
*
* The message class is a kind of a factory object used to create new
* message objects for the protocol it represents (see msg_create()).
*
* The message class object contains all the information needed to parse a
* message. It used when headers are added or removed from the message. When
* a message is sent, the message class is used to order message components
* and print (encode) the message in text format.
*
* The message class contains reference objects to headers and other components
* within the message. Each reference contains a pointer to a @ref
* msg_hclass_s "header class" and a offset to the header objects within
* public message structure. The parser engine uses these references when it
* adds a newly parsed header object to the message structure. The function
* msg_find_hclass() searches for the reference of the named header.
* The application can make a copy of existing message class object using
* the function msg_mclass_clone(). New headers can be added to the message
* class with the msg_mclass_insert_header() and msg_mclass_insert()
* functions. The message class of an existing message object can be found
* out with the function msg_mclass().
*
* @sa sip_default_mclass(), http_default_mclass(), msg_create(),
* msg_mclass(), msg_mclass_clone(), msg_mclass_insert_header(),
* msg_mclass_insert_with_mask(), msg_mclass_insert().
*/
struct msg_mclass_s
{
struct msg_hclass_s
mc_hclass[1]; /**< Recursive header class */
char const *mc_name; /**< Protocol name, e.g., "SIP/2.0" */
void *mc_tag; /**< Protocol-specific tag */
unsigned mc_flags; /**< Default flags */
unsigned mc_msize; /**< Size of public message structure */
/** Function extracting the message contents. */
issize_t (*mc_extract_body)(msg_t *msg, msg_pub_t *pub,
char b[], isize_t bsiz, int eos);
msg_href_t mc_request[1]; /**< Request line reference */
msg_href_t mc_status[1]; /**< Status line reference */
msg_href_t mc_separator[1];/**< Separator line reference */
msg_href_t mc_payload[1]; /**< Message body reference */
msg_href_t mc_unknown[1]; /**< Reference for unknown headers */
msg_href_t mc_error[1]; /**< Reference for erroneous header */
msg_href_t mc_multipart[1];/**< Multipart body reference */
msg_href_t const *
mc_short; /**< Short forms (or NULL) */
short mc_hash_size; /**< Size of parsing table */
short mc_hash_used; /**< Number of headers in parsing table */
/** Hash table for parsing containing reference for each header. */
msg_href_t mc_hash[MC_HASH_SIZE];
};
enum { msg_mclass_copy = 0, msg_mclass_empty = 1 };
SOFIAPUBFUN msg_mclass_t *msg_mclass_clone(msg_mclass_t const *old,
int newsize, int empty);
SOFIAPUBFUN int msg_mclass_insert(msg_mclass_t *mc, msg_href_t const *hr);
SOFIAPUBFUN
int msg_mclass_insert_header(msg_mclass_t *mc,
msg_hclass_t *hc,
unsigned short offset);
SOFIAPUBFUN
int msg_mclass_insert_with_mask(msg_mclass_t *mc,
msg_hclass_t *hc,
unsigned short offset,
unsigned short mask);
SOFIAPUBFUN
msg_href_t const *msg_find_hclass(msg_mclass_t const *, char const *, isize_t *);
SOFIAPUBFUN msg_mclass_t const *msg_mclass(msg_t const *);
SOFIA_END_DECLS
#endif /* !defined(MSG_MCLASS_H) */
@@ -0,0 +1,77 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_MCLASS_HASH_H
/** Defined when <sofia-sip/msg_mclass_hash.h> has been included. */
#define MSG_MCLASS_HASH_H
/**@ingroup msg_parser
* @file sofia-sip/msg_mclass_hash.h
*
* Hash function for header names.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Aug 21 16:03:45 2001 ppessi
*
*/
#include <sofia-sip/su_config.h>
#ifndef BNF_H
#include <sofia-sip/bnf.h>
#endif
SOFIA_BEGIN_DECLS
/** Hash the header name */
#define MC_HASH(s, n) (msg_header_name_hash(s, NULL) % (unsigned)(n))
/** Hash header name */
static inline
unsigned short msg_header_name_hash(char const *s, isize_t *llen)
{
unsigned short hash = 0;
size_t i;
for (i = 0; s[i]; i++) {
unsigned char c = s[i];
if (!(_bnf_table[c] & bnf_token))
break;
if (c >= 'A' && c <= 'Z')
hash += (c + 'a' - 'A');
else
hash += c;
hash *= 38501U;
}
if (llen)
*llen = i;
return hash;
}
SOFIA_END_DECLS
#endif /** MSG_MCLASS_HASH_H */
@@ -0,0 +1,242 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_MIME_H
/** Defined when <sofia-sip/msg_mime.h> has been included. */
#define MSG_MIME_H
/**@ingroup msg_mime
* @file sofia-sip/msg_mime.h
*
* MIME headers and multipart messages (@RFC2045).
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi
*
*/
#ifndef URL_H
#include <sofia-sip/url.h>
#endif
#ifndef MSG_TYPES_H
#include <sofia-sip/msg_types.h>
#endif
#ifndef SU_TYPES_H
#include <sofia-sip/su_types.h>
#endif
SOFIA_BEGIN_DECLS
typedef struct msg_accept_any_s msg_accept_any_t;
typedef struct msg_accept_s msg_accept_t;
typedef msg_accept_any_t msg_accept_charset_t;
typedef msg_accept_any_t msg_accept_encoding_t;
typedef msg_accept_any_t msg_accept_language_t;
typedef struct msg_content_disposition_s
msg_content_disposition_t;
typedef msg_list_t msg_content_encoding_t;
typedef msg_generic_t msg_content_id_t;
typedef struct msg_content_length_s msg_content_length_t;
typedef msg_generic_t msg_content_location_t;
typedef msg_list_t msg_content_language_t;
typedef msg_generic_t msg_content_md5_t;
typedef msg_generic_t msg_content_transfer_encoding_t;
typedef struct msg_content_type_s msg_content_type_t;
typedef msg_generic_t msg_mime_version_t;
typedef struct msg_warning_s msg_warning_t;
/** Multipart body object. */
typedef struct msg_multipart_s msg_multipart_t;
/**@ingroup msg_accept
* @brief Structure for @b Accept header.
*/
struct msg_accept_s
{
msg_common_t ac_common[1]; /**< Common fragment info */
msg_accept_t *ac_next; /**< Pointer to next Accept header */
char const *ac_type; /**< Pointer to type/subtype */
char const *ac_subtype; /**< Points after first slash in type */
msg_param_t const *ac_params; /**< List of parameters */
char const *ac_q; /**< Value of q parameter */
};
/**@ingroup msg_accept_encoding
* @brief Structure for @b Accept-Charset, @b Accept-Encoding and
* @b Accept-Language headers.
*/
struct msg_accept_any_s
{
msg_common_t aa_common[1]; /**< Common fragment info */
msg_accept_any_t *aa_next; /**< Pointer to next Accept-* header */
char const *aa_value; /**< Token */
msg_param_t const *aa_params; /**< List of parameters */
char const *aa_q; /**< Value of q parameter */
};
/**@ingroup msg_content_disposition
* @brief Structure for @b Content-Disposition header.
*/
struct msg_content_disposition_s
{
msg_common_t cd_common[1]; /**< Common fragment info */
msg_error_t *cd_next; /**< Link to next (dummy) */
char const *cd_type; /**< Disposition type */
msg_param_t const *cd_params; /**< List of parameters */
char const *cd_handling; /**< Value of @b handling parameter */
unsigned cd_required:1; /**< True if handling=required */
unsigned cd_optional:1; /**< True if handling=optional */
unsigned :0; /* pad */
};
/**@ingroup msg_content_length
* @brief Structure for Content-Length header.
*/
struct msg_content_length_s
{
msg_common_t l_common[1]; /**< Common fragment info */
msg_error_t *l_next; /**< Link to next (dummy) */
unsigned long l_length; /**< Digits */
};
/**@ingroup msg_content_type
* @brief Structure for Content-Type header.
*/
struct msg_content_type_s
{
msg_common_t c_common[1]; /**< Common fragment info */
msg_error_t *c_next; /**< Dummy link to next */
char const *c_type; /**< Pointer to type/subtype */
char const *c_subtype; /**< Points after first slash in type */
msg_param_t const *c_params; /**< List of parameters */
};
/**@ingroup sip_warning
* @brief Structure for @b Warning header.
*/
struct msg_warning_s
{
msg_common_t w_common[1]; /**< Common fragment info */
msg_warning_t *w_next; /**< Link to next Warning header */
unsigned w_code; /**< Warning code */
char const *w_host; /**< Hostname or pseudonym */
char const *w_port; /**< Port number */
char const *w_text; /**< Warning text */
};
/**@ingroup msg_multipart
*
* @brief Structure for a part in MIME multipart message.
*/
struct msg_multipart_s
{
msg_common_t mp_common[1]; /**< Common fragment information */
msg_multipart_t *mp_next; /**< Next part in multipart body */
/* Preamble for this part */
char *mp_data; /**< Boundary string. */
usize_t mp_len; /**< Length of boundary (mp_data).*/
unsigned mp_flags;
msg_error_t *mp_error;
/* === Headers start here */
msg_content_type_t *mp_content_type; /**< Content-Type */
msg_content_disposition_t *mp_content_disposition;
/**< Content-Disposition */
msg_content_location_t *mp_content_location; /**< Content-Location */
msg_content_id_t *mp_content_id; /**< Content-ID */
msg_content_language_t *mp_content_language; /**< Content-Language */
msg_content_encoding_t *mp_content_encoding; /**< Content-Encoding */
msg_content_transfer_encoding_t *mp_content_transfer_encoding;
/**< Content-Transfer-Encoding */
#if 0
/* === Hash headers end here */
/* These MIME headers are here for msg_parser.awk */
msg_accept_t *mp_accept; /**< Accept */
msg_accept_charset_t *mp_accept_charset; /**< Accept-Charset */
msg_accept_encoding_t *mp_accept_encoding; /**< Accept-Encoding */
msg_accept_language_t *mp_accept_language; /**< Accept-Language */
msg_mime_version_t *mp_mime_version; /**< MIME-Version */
msg_content_md5_t *mp_content_md5; /**< Content-MD5 */
msg_content_length_t *mp_content_length; /**< Content-Length */
msg_multipart_t *mp_multipart; /**< Recursive multipart */
msg_warning_t *mp_warning; /**< Warning */
#endif
/* === Headers end here */
/** Unknown and extra headers. */
msg_unknown_t *mp_unknown; /**< Unknown headers */
msg_separator_t *mp_separator; /**< Separator */
msg_payload_t *mp_payload; /**< Body part */
msg_multipart_t *mp_multipart; /**< Recursive multipart */
msg_payload_t *mp_close_delim; /**< Closing delimiter */
};
SOFIAPUBFUN
msg_multipart_t *msg_multipart_create(su_home_t *home,
char const *content_type,
void const *data,
isize_t dlen);
SOFIAPUBFUN
msg_multipart_t *msg_multipart_parse(su_home_t *home,
msg_content_type_t const *c,
msg_payload_t *pl);
SOFIAPUBFUN
int msg_multipart_complete(su_home_t *home,
msg_content_type_t *c,
msg_multipart_t *mp);
SOFIAPUBFUN msg_header_t *msg_multipart_serialize(msg_header_t **head0,
msg_multipart_t *mp);
SOFIAPUBFUN issize_t msg_multipart_prepare(msg_t *msg, msg_multipart_t *mp, int flags);
SOFIAPUBFUN isize_t msg_accept_any_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_accept_any_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b, isize_t xtra);
SOFIAPUBFUN
msg_content_length_t *msg_content_length_create(su_home_t *home, uint32_t n);
/** MIME multipart protocol name. @HIDE */
#define MSG_MULTIPART_VERSION_CURRENT msg_mime_version_1_0
SOFIAPUBVAR char const msg_mime_version_1_0[];
/** MIME multipart parser table identifier. @HIDE */
#define MSG_MULTIPART_PROTOCOL_TAG ((void *)0x4d494d45) /* 'MIME' */
SOFIA_END_DECLS
#endif /** MSG_MIME_H */
@@ -0,0 +1,323 @@
/**@ingroup msg -*- c -*-
* @file sofia-sip/msg_mime_protos.h.in
*
* Template for <msg_mime_protos.h>.
*/
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_MIME_PROTOS_H
/** Defined when <sofia-sip/msg_mime_protos.h> has been included. */
#define MSG_MIME_PROTOS_H
/**@ingroup msg_mime
* @file sofia-sip/msg_mime_protos.h
*
* Prototypes for MIME headers (@RFC2045).
*
* #AUTO#
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*/
#ifndef MSG_PARSER_H
#include <sofia-sip/msg_parser.h>
#endif
#ifndef MSG_MIME_H
#include <sofia-sip/msg_mime.h>
#endif
#ifndef MSG_MCLASS_H
#include <sofia-sip/msg_mclass.h>
#endif
#ifndef MSG_MCLASS_H
#include <sofia-sip/msg_mclass.h>
#endif
SOFIA_BEGIN_DECLS
MSG_DLL extern msg_mclass_t const msg_multipart_mclass[1];
#define msg_multipart_class ((msg_hclass_t *)msg_multipart_mclass)
/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
/**@addtogroup msg_#xxxxxx#
* @{
*/
enum {
/** Hash of #xxxxxxx_xxxxxxx#. @internal */
msg_#xxxxxx#_hash = #hash#
};
/** Parse a #xxxxxxx_xxxxxxx#. @internal */
MSG_DLL msg_parse_f msg_#xxxxxx#_d;
/** Print a #xxxxxxx_xxxxxxx#. @internal */
MSG_DLL msg_print_f msg_#xxxxxx#_e;
MSG_DLL msg_xtra_f msg_#xxxxxx#_dup_xtra;
MSG_DLL msg_dup_f msg_#xxxxxx#_dup_one;
/**Header class for #xxxxxxx_xxxxxxx#.
*
* The header class msg_#xxxxxx#_class defines how a
* #xxxxxxx_xxxxxxx# header is parsed and printed. It also
* contains methods used by message parser and other functions
* to manipulate the #msg_#xxxxxx#_t header structure.
*
*/
#ifndef msg_#xxxxxx#_class
MSG_DLL extern msg_hclass_t msg_#xxxxxx#_class[];
#endif
/**Initializer for an #msg_#xxxxxx#_t structure.
*
* A static msg_#xxxxxx#_t structure must be initialized
* with the MSG_#XXXXXX#_INIT() macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
*
* @endcode
* @HI
*/
#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
/**Initialize an #msg_#xxxxxx#_t structure.
*
* An #msg_#xxxxxx#_t structure can be initialized with the
* msg_#xxxxxx#_init() function/macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx#;
*
* msg_#xxxxxx#_init(&msg_#xxxxxx#);
*
* @endcode
*
* @param x pointer to #msg_#xxxxxx#_t structure
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
{
return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
}
#else
#define msg_#xxxxxx#_init(x) \
MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
#endif
/**Test if header object is an instance of #msg_#xxxxxx#_t.
*
* The function msg_is_#xxxxxx#() returns true (nonzero) if
* the header class is an instance of #xxxxxxx_xxxxxxx#
* object and false (zero) otherwise.
*
* @param header pointer to the header structure to be tested
*
* @return The function msg_is_#xxxxxx#() returns true (nonzero) if the
* header object is an instance of header #xxxxxxx_xxxxxxx# and false (zero)
* otherwise.
*/
#if SU_HAVE_INLINE
su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
{
return header && header->sh_class->hc_hash == msg_#xxxxxx#_hash;
}
#else
int msg_is_#xxxxxx#(msg_header_t const *header);
#endif
#define msg_#xxxxxx#_p(h) msg_is_#xxxxxx#((h))
/**Duplicate (deep copy) #msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_dup() duplicates a header structure @a
* header. If the header structure @a header contains a reference
* (@c header->x_next) to a list of headers, all the headers in the
* list are duplicated, too.
*
* @param home memory home used to allocate new structure
* @param header header structure to be duplicated
*
* When duplicating, all parameter lists and non-constant strings
* attached to the header are copied, too. The function uses given
* memory @a home to allocate all the memory areas used to copy the
* header.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_dup(home, msg->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_dup() returns a pointer to the
* newly duplicated #msg_#xxxxxx#_t header structure, or NULL
* upon an error.
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home,
msg_#xxxxxx#_t const *header);
#if SU_HAVE_INLINE
su_inline
msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home,
msg_#xxxxxx#_t const *header)
{
return (msg_#xxxxxx#_t *)
msg_header_dup_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header);
}
#endif
/**Copy an #msg_#xxxxxx#_t header structure.
*
* The function msg_#xxxxxx#_copy() copies a header structure @a
* header. If the header structure @a header contains a reference
* (@c header->h_next) to a list of headers, all the headers in that
* list are copied, too. The function uses given memory @a home to
* allocate all the memory areas used to copy the header structure
* @a header.
*
* @param home memory home used to allocate new structure
* @param header pointer to the header structure to be duplicated
*
* When copying, only the header structure and parameter lists
* attached to it are duplicated. The new header structure retains
* all the references to the strings within the old @a header,
* including the encoding of the old header, if present.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_copy(home, msg->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_copy() returns a pointer to
* newly copied header structure, or NULL upon an error.
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home,
msg_#xxxxxx#_t const *header);
#if SU_HAVE_INLINE
su_inline
msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home,
msg_#xxxxxx#_t const *header)
{
return (msg_#xxxxxx#_t *)
msg_header_copy_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header);
}
#endif
/**Make a header structure #msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_make() makes a new #msg_#xxxxxx#_t header
* structure. It allocates a new header structure, and decodes the string @a
* s as the value of the structure.
*
* @param home memory home used to allocate new header structure.
* @param s string to be decoded as value of the new header structure
*
* @note This function may be implemented as a macro calling
* msg_header_make().
*
* @return
* The function msg_#xxxxxx#_make() returns a pointer to newly maked
* #msg_#xxxxxx#_t header structure, or NULL upon an error.
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
{
return (msg_#xxxxxx#_t*)msg_header_make(home, msg_#xxxxxx#_class, s);
}
#else
msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s);
#endif
/**Make a #xxxxxxx_xxxxxxx# from formatting result.
*
* The function msg_#xxxxxx#_format() makes a new #xxxxxxx_xxxxxxx# object
* using snprintf-formatted result as its value. The function first
* prints the arguments according to the format @a fmt specified. Then it
* allocates a new header structure, and uses the formatting result as the
* header value.
*
* @param home memory home used to allocate new header structure.
* @param fmt string used as a printf()-style format
* @param ... argument list for format
*
* @note This function may be implemented as a macro calling
* msg_header_format().
*
* @return
* The function msg_#xxxxxx#_format() returns a pointer to newly
* makes header structure, or NULL upon an error.
*
* @HIDE
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
{
msg_header_t *h;
va_list ap;
va_start(ap, fmt);
h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
va_end(ap);
return (msg_#xxxxxx#_t*)h;
}
#endif
/** @} */
/* Internal prototypes */
MSG_DLL msg_update_f msg_accept_update;
MSG_DLL msg_update_f msg_accept_any_update;
MSG_DLL msg_update_f msg_content_disposition_update;
SOFIA_END_DECLS
#endif /** !defined(MSG_MIME_PROTOS_H) */
@@ -0,0 +1,309 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_PARSER_H
/** Defined when <sofia-sip/msg_parser.h> has been included. */
#define MSG_PARSER_H
/**@ingroup msg_parser
* @file sofia-sip/msg_parser.h
*
* Message parser interface.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Aug 21 16:03:45 2001 ppessi
*
*/
#ifndef SU_ALLOC_H
#include <sofia-sip/su_alloc.h>
#endif
#ifndef MSG_HEADER_H
#include <sofia-sip/msg_header.h>
#endif
#ifndef BNF_H
#include <sofia-sip/bnf.h>
#endif
#ifndef URL_H
#include <sofia-sip/url.h>
#endif
SOFIA_BEGIN_DECLS
/* ---------------------------------------------------------------------------
* 1) Header class definitions.
*/
#if HAVE_STRUCT_KEYWORDS
/** Define a header class */
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
hc_hash: pr##c##_hash, \
hc_parse: pr##c##_d, \
hc_print: pr##c##_e, \
hc_dxtra: dup##_dup_xtra, \
hc_dup_one: dup##_dup_one, \
hc_update: upd##_update, \
hc_name: l, \
hc_len: sizeof(l) - 1, \
hc_short: s, \
hc_size: MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
hc_params: offsetof(pr##c##_t, params), \
hc_kind: msg_kind_##kind, \
}}
#else
#define MSG_HEADER_CLASS(pr, c, l, s, params, kind, dup, upd) \
{{ \
pr##c##_hash, \
pr##c##_d, \
pr##c##_e, \
dup##_dup_xtra, \
dup##_dup_one, \
upd##_update, \
l, \
sizeof(l) - 1, \
s, \
MSG_ALIGN(sizeof(pr##c##_t), sizeof(void*)), \
offsetof(pr##c##_t, params), \
msg_kind_##kind, \
}}
#endif
/* Mark headers critical for understanding the message */
#define msg_kind_single_critical msg_kind_single, 1
#define msg_kind_list_critical msg_kind_list, 1
SOFIAPUBFUN issize_t msg_extract_header(msg_t *msg, msg_pub_t *mo,
char b[], isize_t bsiz, int eos);
SOFIAPUBFUN issize_t msg_extract_separator(msg_t *msg, msg_pub_t *mo,
char b[], isize_t bsiz, int eos);
SOFIAPUBFUN issize_t msg_extract_payload(msg_t *msg, msg_pub_t *mo,
msg_header_t **return_payload,
usize_t body_len,
char b[], isize_t bsiz, int eos);
/* ---------------------------------------------------------------------------
* 2) Header processing methods for common headers.
*/
SOFIAPUBFUN int msg_firstline_d(char *s, char **ss2, char **ss3);
SOFIAPUBFUN isize_t msg_default_dup_xtra(msg_header_t const *header, isize_t offset);
SOFIAPUBFUN char *msg_default_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra);
SOFIAPUBFUN issize_t msg_numeric_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
SOFIAPUBFUN issize_t msg_numeric_e(char [], isize_t, msg_header_t const *, int);
SOFIAPUBFUN issize_t msg_list_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
SOFIAPUBFUN issize_t msg_list_e(char [], isize_t, msg_header_t const *, int);
SOFIAPUBFUN isize_t msg_list_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_list_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b, isize_t xtra);
SOFIAPUBFUN issize_t msg_generic_d(su_home_t *, msg_header_t *, char *, isize_t);
SOFIAPUBFUN issize_t msg_generic_e(char [], isize_t, msg_header_t const *, int);
SOFIAPUBFUN isize_t msg_generic_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_generic_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b,
isize_t xtra);
SOFIAPUBFUN isize_t msg_unknown_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_unknown_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b, isize_t xtra);
SOFIAPUBFUN isize_t msg_error_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_error_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b, isize_t xtra);
SOFIAPUBFUN issize_t msg_payload_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
SOFIAPUBFUN issize_t msg_payload_e(char b[], isize_t bsiz, msg_header_t const *, int f);
SOFIAPUBFUN isize_t msg_payload_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_payload_dup_one(msg_header_t *dst,
msg_header_t const *src,
char *b, isize_t xtra);
SOFIAPUBFUN issize_t msg_separator_d(su_home_t *, msg_header_t *, char *, isize_t);
SOFIAPUBFUN issize_t msg_separator_e(char [], isize_t, msg_header_t const *, int);
SOFIAPUBFUN issize_t msg_auth_d(su_home_t *, msg_header_t *h, char *s, isize_t slen);
SOFIAPUBFUN issize_t msg_auth_e(char b[], isize_t bsiz, msg_header_t const *h, int f);
SOFIAPUBFUN isize_t msg_auth_dup_xtra(msg_header_t const *h, isize_t offset);
SOFIAPUBFUN char *msg_auth_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra);
/* ---------------------------------------------------------------------------
* 2) Macros and prototypes for building header decoding/encoding functions.
*/
#define MSG_HEADER_DATA(h) ((char *)(h) + (h)->sh_class->hc_size)
#define MSG_HEADER_TEST(h) ((h) && (h)->sh_class)
su_inline void *msg_header_data(msg_frg_t *h);
SOFIAPUBFUN int msg_hostport_d(char **ss,
char const **return_host,
char const **return_port);
SOFIAPUBFUN issize_t msg_token_d(char **ss, char const **return_token);
SOFIAPUBFUN issize_t msg_uint32_d(char **ss, uint32_t *return_value);
SOFIAPUBFUN issize_t msg_comment_d(char **ss, char const **return_comment);
SOFIAPUBFUN issize_t msg_quoted_d(char **ss, char **return_unquoted);
SOFIAPUBFUN issize_t msg_unquoted_e(char *b, isize_t bsiz, char const *s);
SOFIAPUBFUN issize_t msg_parse_next_field(su_home_t *home, msg_header_t *prev,
char *s, isize_t slen);
/** Terminate encoding. @HI */
#define MSG_TERM_E(p, e) ((p) < (e) ? (p)[0] = '\0' : '\0')
/** Encode a character. @HI */
#define MSG_CHAR_E(p, e, c) (++(p) < (e) ? ((p)[-1]=(c)) : (c))
/** Calculate separator and string length. @HI */
#define MSG_STRING_LEN(s, sep_size) ((s) ? (strlen(s) + sep_size) : 0)
/** Encode a string. @HI */
#define MSG_STRING_E(p, e, s) do { \
size_t _n = strlen(s); if (p + _n+1 < e) memcpy(p, s, _n+1); p+= _n; } while(0)
/** Duplicate string. @HI */
#define MSG_STRING_DUP(p, d, s) \
(void)((s)?((p)=(char*)memccpy((void *)((d)=(char*)p),(s),0,SIZE_MAX))\
:((d)=NULL))
/** Calculate string size. @HI */
#define MSG_STRING_SIZE(s) ((s) ? (strlen(s) + 1) : 0)
SOFIAPUBFUN issize_t msg_commalist_d(su_home_t *, char **ss,
msg_param_t **append_list,
issize_t (*scanner)(char *s));
SOFIAPUBFUN issize_t msg_token_scan(char *start);
SOFIAPUBFUN issize_t msg_attribute_value_scanner(char *s);
SOFIAPUBFUN issize_t msg_any_list_d(su_home_t *, char **ss,
msg_param_t **append_list,
issize_t (*scanner)(char *s),
int sep);
/** Encode a comma-separated parameter list */
#define MSG_COMMALIST_E(b, end, params, compact) do { \
char const * const *p_; char const * c_ = ""; \
for (p_ = (params); p_ && *p_; p_++, c_ = (compact ? "," : ", ")) \
{ MSG_STRING_E(b, (end), c_); MSG_STRING_E(b, (end), *p_); } \
} while(0)
/* Parameter lists */
SOFIAPUBFUN int msg_header_update_params(msg_common_t *h, int clear);
/** Match a parameter with any value. @HI */
#define MSG_PARAM_MATCH(v, s, name) \
(strncasecmp(s, name "=", sizeof(name)) == 0 ? (v = s + sizeof(name)) : NULL)
/** Match a parameter with known value. @HI */
#define MSG_PARAM_MATCH_P(v, s, name) \
((strncasecmp((s), name "", sizeof(name) - 1) == 0 && \
((s)[sizeof(name) - 1] == '=' || (s)[sizeof(name) - 1] == '\0')) ? \
((v) = 1) : 0)
/** Calculate allocated number of items in parameter list. @HI */
#define MSG_PARAMS_NUM(n) (((n) + MSG_N_PARAMS - 1) & (size_t)(0 - MSG_N_PARAMS))
/** Parse a semicolong-separated attribute-value list. @HI */
SOFIAPUBFUN issize_t msg_avlist_d(su_home_t *, char **ss,
msg_param_t const **return_params);
/** Parse a semicolon-separated parameter list starting with semicolon. @HI */
SOFIAPUBFUN issize_t msg_params_d(su_home_t *, char **ss,
msg_param_t const **return_params);
/** Encode a list of parameters. */
SOFIAPUBFUN isize_t msg_params_e(char b[], isize_t bsiz, msg_param_t const pparams[]);
/** Join list of parameters */
SOFIAPUBFUN issize_t msg_params_join(su_home_t *,
msg_param_t **dst,
msg_param_t const *src,
unsigned prune,
int dup);
/** Encode a list of parameters. @HI */
#define MSG_PARAMS_E(b, end, params, flags) \
(b) += msg_params_e((b), (size_t)((b) < (end) ? (end) - (b) : 0), (params))
/** Calculate extra size of parametes. @HI */
#define MSG_PARAMS_SIZE(rv, params) (rv = msg_params_dup_xtra(params, rv))
/** Duplicate a parameter list */
SOFIAPUBFUN char *msg_params_dup(msg_param_t const **d, msg_param_t const *s,
char *b, isize_t xtra);
/** Count number of parameters in the list */
su_inline isize_t msg_params_count(msg_param_t const params[])
{
if (params) {
size_t n;
for (n = 0; params[n]; n++)
;
return n;
}
else {
return 0;
}
}
/** Calculate memory size required by parameter list */
su_inline isize_t msg_params_dup_xtra(msg_param_t const params[], isize_t offset)
{
isize_t n = msg_params_count(params);
if (n) {
MSG_STRUCT_SIZE_ALIGN(offset);
offset += MSG_PARAMS_NUM(n + 1) * sizeof(msg_param_t);
for (n = 0; params[n]; n++)
offset += strlen(params[n]) + 1;
}
return offset;
}
/** Return pointer to extra data after header structure */
su_inline void *msg_header_data(msg_frg_t *h)
{
if (h)
return (char *)h + h->h_class->hc_size;
else
return NULL;
}
SOFIA_END_DECLS
#endif /** MSG_PARSER_H */
@@ -0,0 +1,311 @@
/**@ingroup msg_headers -*- C -*-
* @file sofia-sip/msg_protos.h.in
*
* Template for <msg_protos.h>.
*/
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_PROTOS_H
/** Defined when <sofia-sip/msg_protos.h> has been included. */
#define MSG_PROTOS_H
/**@ingroup msg_headers
* @file sofia-sip/msg_protos.h
*
* Prototypes for common headers
*
* #AUTO#
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Fri Aug 16 19:18:26 EEST 2002 ppessi
*/
#ifndef MSG_HEADER_H
#include <sofia-sip/msg_header.h>
#endif
SOFIA_BEGIN_DECLS
enum {
msg_request_hash = -1,
msg_status_hash = -2
};
/* Declare internal prototypes for #xxxxxxx_xxxxxxx# */
/**@addtogroup msg_#xxxxxx#
* @{
*/
enum {
/** Hash of #xxxxxxx_xxxxxxx#. @internal */
msg_#xxxxxx#_hash = #hash#
};
/** Parse a #xxxxxxx_xxxxxxx#. @internal */
MSG_DLL msg_parse_f msg_#xxxxxx#_d;
/** Print a #xxxxxxx_xxxxxxx#. @internal */
MSG_DLL msg_print_f msg_#xxxxxx#_e;
/**Header class for #xxxxxxx_xxxxxxx#.
*
* The header class msg_#xxxxxx#_class defines how a
* #xxxxxxx_xxxxxxx# header is parsed and printed. It also
* contains methods used by message parser and other functions
* to manipulate the msg_#xxxxxx#_t header structure.
*
*/
MSG_DLL extern msg_hclass_t msg_#xxxxxx#_class[];
/**Initializer for structure msg_#xxxxxx#_t.
*
* A static msg_#xxxxxx#_t structure must be initialized
* with the MSG_#XXXXXX#_INIT() macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
*
* @endcode
* @HI
*/
#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
/**Initialize a structure msg_#xxxxxx#_t.
*
* An msg_#xxxxxx#_t structure can be initialized with the
* msg_#xxxxxx#_init() function/macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx#;
*
* msg_#xxxxxx#_init(&msg_#xxxxxx#);
*
* @endcode
*
* @param x pointer to msg_#xxxxxx#_t structure
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
{
return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
}
#else
#define msg_#xxxxxx#_init(x) \
MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
#endif
/**Test if header object is instance of msg_#xxxxxx#_t.
*
* The function msg_is_#xxxxxx#() returns true (nonzero) if
* the header class is an instance of #xxxxxxx_xxxxxxx#
* object and false (zero) otherwise.
*
* @param header pointer to the header structure to be tested
*
* @return
* The function msg_is_#xxxxxx#() returns true (nonzero) if
* the header object is an instance of header #xxxxxx# and
* false (zero) otherwise.
*/
#if SU_HAVE_INLINE
su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
{
msg_generic_t const *h = (msg_generic_t *)header;
return h && h->g_common->h_class->hc_hash == msg_#xxxxxx#_hash;
}
#else
int msg_is_#xxxxxx#(msg_header_t const *header);
#endif
/**Duplicate (deep copy) @c msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_dup() duplicates a header structure @a
* header. If the header structure @a header contains a reference
* (@c header->x_next) to a list of headers, all the headers in the
* list are duplicated, too.
*
* @param home memory home used to allocate new structure
* @param header header structure to be duplicated
*
* When duplicating, all parameter lists and non-constant strings
* attached to the header are copied, too. The function uses given
* memory @a home to allocate all the memory areas used to copy the
* header.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_dup(home, msg->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_dup() returns a pointer to the
* newly duplicated msg_#xxxxxx#_t header structure, or NULL
* upon an error.
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home,
msg_#xxxxxx#_t const *header)
__attribute__((__malloc__));
#if SU_HAVE_INLINE
su_inline
msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home,
msg_#xxxxxx#_t const *header)
{
return (msg_#xxxxxx#_t *)
msg_header_dup_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header);
}
#endif
/**Copy a msg_#xxxxxx#_t header structure.
*
* The function msg_#xxxxxx#_copy() copies a header structure @a
* header. If the header structure @a header contains a reference
* (@c header->h_next) to a list of headers, all the headers in that
* list are copied, too. The function uses given memory @a home to
* allocate all the memory areas used to copy the header structure
* @a header.
*
* @param home memory home used to allocate new structure
* @param header pointer to the header structure to be duplicated
*
* When copying, only the header structure and parameter lists
* attached to it are duplicated. The new header structure retains
* all the references to the strings within the old @a header,
* including the encoding of the old header, if present.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_copy(home, msg->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_copy() returns a pointer to
* newly copied header structure, or NULL upon an error.
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home,
msg_#xxxxxx#_t const *header)
__attribute__((__malloc__));
#if SU_HAVE_INLINE
su_inline
msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home,
msg_#xxxxxx#_t const *header)
{
return (msg_#xxxxxx#_t *)
msg_header_copy_as(home, msg_#xxxxxx#_class, (msg_header_t const *)header);
}
#endif
/**Make a header structure msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_make() makes a new
* msg_#xxxxxx#_t header structure. It allocates a new
* header structure, and decodes the string @a s as the
* value of the structure.
*
* @param home memory home used to allocate new header structure.
* @param s string to be decoded as value of the new header structure
*
* @note This function is usually implemented as a macro calling
* msg_header_make().
*
* @return
* The function msg_#xxxxxx#_make() returns a pointer to
* newly maked msg_#xxxxxx#_t header structure, or NULL upon
* an error.
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
{
return (msg_#xxxxxx#_t*)msg_header_make(home, msg_#xxxxxx#_class, s);
}
#else
msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
__attribute__((__malloc__));
#endif
/**Make a #xxxxxxx_xxxxxxx# from formatting result.
*
* The function msg_#xxxxxx#_format() makes a new
* #xxxxxxx_xxxxxxx# object using formatting result as its
* value. The function first prints the arguments according to
* the format @a fmt specified. Then it allocates a new header
* structure, and uses the formatting result as the header
* value.
*
* @param home memory home used to allocate new header structure.
* @param fmt string used as a printf()-style format
* @param ... argument list for format
*
* @note This function is usually implemented as a macro calling
* msg_header_format().
*
* @return
* The function msg_#xxxxxx#_format() returns a pointer to newly
* makes header structure, or NULL upon an error.
*
* @HIDE
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
__attribute__((__malloc__, __format__ (printf, 2, 3)));
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
{
msg_header_t *h;
va_list ap;
va_start(ap, fmt);
h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
va_end(ap);
return (msg_#xxxxxx#_t*)h;
}
#endif
/** @} */
SOFIA_END_DECLS
#endif /** !defined(MSG_PROTOS_H) */
@@ -0,0 +1,65 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_TAG_CLASS_H
/** Defined when <sofia-sip/msg_tag_class.h> has been included */
#define MSG_TAG_CLASS_H
/**@file sofia-sip/msg_tag_class.h
* @brief Functions for constructing per-protocol tag classes.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Wed Feb 21 11:01:45 2001 ppessi
*/
#ifndef SU_TAG_H
#include <sofia-sip/su_tag.h>
#endif
SOFIA_BEGIN_DECLS
SOFIAPUBFUN int msghdrtag_snprintf(tagi_t const *t, char b[], size_t size);
SOFIAPUBFUN size_t msghdrtag_xtra(tagi_t const *t, size_t offset);
SOFIAPUBFUN tagi_t *msghdrtag_dup(tagi_t *dst, tagi_t const *src,
void **inout_buffer);
SOFIAPUBFUN int msghdrtag_scan(tag_type_t tt, su_home_t *home,
char const *s,
tag_value_t *return_value);
SOFIAPUBFUN tagi_t *msghdrtag_filter(tagi_t *dst, tagi_t const f[],
tagi_t const *src,
void **inout_buffer);
SOFIAPUBFUN tagi_t *msgstrtag_filter(tagi_t *dst, tagi_t const f[],
tagi_t const *src,
void **inout_buffer);
SOFIAPUBFUN int msgobjtag_snprintf(tagi_t const *t, char b[], size_t size);
SOFIAPUBFUN size_t msgobjtag_xtra(tagi_t const *t, size_t offset);
SOFIAPUBFUN tagi_t *msgobjtag_dup(tagi_t *dst, tagi_t const *src,
void **inout_buffer);
SOFIA_END_DECLS
#endif /** !defined(MSG_TAG_CLASS_H) */
@@ -0,0 +1,301 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef MSG_TYPES_H
/** Defined when <sofia-sip/msg_types.h> has been included. */
#define MSG_TYPES_H
/**@file sofia-sip/msg_types.h
* @brief Types for messages and common headers
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jan 23 15:43:17 2003 ppessi
*
*/
#ifndef SU_TYPES_H
#include <sofia-sip/su_types.h>
#endif
SOFIA_BEGIN_DECLS
/** Message class. */
typedef struct msg_mclass_s msg_mclass_t;
/** Header class. */
typedef struct msg_hclass_s const msg_hclass_t;
/** Header reference. */
typedef struct msg_href_s msg_href_t;
/** Message object. */
typedef struct msg_s msg_t;
#ifndef MSG_TIME_T_DEFINED
#define MSG_TIME_T_DEFINED
/** Time in seconds since epoch (1900-Jan-01 00:00:00). */
typedef unsigned long msg_time_t;
#endif
#ifndef MSG_TIME_MAX
/** Latest time that can be expressed with msg_time_t. @HIDE */
#define MSG_TIME_MAX ((msg_time_t)ULONG_MAX)
#endif
#ifndef MSG_PUB_T
#ifdef MSG_OBJ_T
#define MSG_PUB_T MSG_OBJ_T
#else
#define MSG_PUB_T struct msg_pub_s
#endif
#endif
/**Public protocol-specific message structure for accessing the message.
*
* This type can be either #sip_t, #http_t, or #msg_multipart_t, depending
* on the message. The base structure used by msg module is defined in
* struct #msg_pub_s.
*/
typedef MSG_PUB_T msg_pub_t;
#ifndef MSG_HDR_T
#define MSG_HDR_T union msg_header_u
#endif
/** Any protocol-specific header object */
typedef MSG_HDR_T msg_header_t;
typedef struct msg_common_s msg_common_t;
typedef struct msg_separator_s msg_separator_t;
typedef struct msg_payload_s msg_payload_t;
typedef struct msg_unknown_s msg_unknown_t;
typedef struct msg_error_s msg_error_t;
typedef msg_common_t msg_frg_t;
typedef char const *msg_param_t;
typedef struct msg_numeric_s msg_numeric_t;
typedef struct msg_generic_s msg_generic_t;
typedef struct msg_list_s msg_list_t;
typedef struct msg_auth_s msg_auth_t;
typedef struct msg_auth_info_s msg_auth_info_t;
#define MSG_HEADER_N 16377
/** Common part of the header objects (or message fragments).
*
* This structure is also known as #msg_common_t or #sip_common_t.
*/
struct msg_common_s {
msg_header_t *h_succ; /**< Pointer to succeeding fragment. */
msg_header_t **h_prev; /**< Pointer to preceeding fragment. */
msg_hclass_t *h_class; /**< Header class. */
void const *h_data; /**< Fragment data */
usize_t h_len; /**< Fragment length (including CRLF) */
};
/** Message object, common view */
struct msg_pub_s {
msg_common_t msg_common[1]; /**< Recursive */
msg_pub_t *msg_next;
void *msg_user;
unsigned msg_size;
unsigned msg_flags;
msg_error_t *msg_error;
msg_header_t *msg_request;
msg_header_t *msg_status;
msg_header_t *msg_headers[MSG_HEADER_N];
};
#define msg_ident msg_common->h_class
/** Numeric header.
*
* A numeric header has a 32-bit integer as its value.
*/
struct msg_numeric_s {
msg_common_t x_common[1]; /**< Common fragment info */
msg_numeric_t *x_next; /**< Link to next header */
unsigned long x_value; /**< Numeric header value */
};
/** Generic header.
*
* A generic header does not have any internal structure. Its value is
* represented as a string.
*/
struct msg_generic_s {
msg_common_t g_common[1]; /**< Common fragment info */
msg_generic_t *g_next; /**< Link to next header */
char const *g_string; /**< Header value */
};
/** List header.
*
* A list header consists of comma-separated list of tokens.
*/
struct msg_list_s {
msg_common_t k_common[1]; /**< Common fragment info */
msg_list_t *k_next; /**< Link to next header */
msg_param_t *k_items; /**< List of items */
};
/** Authentication header.
*
* An authentication header has authentication scheme name and
* comma-separated list of parameters as its value.
*/
struct msg_auth_s {
msg_common_t au_common[1]; /**< Common fragment info */
msg_auth_t *au_next; /**< Link to next header */
char const *au_scheme; /**< Auth-scheme like Basic or Digest */
msg_param_t const *au_params; /**< Comma-separated parameters */
};
/**Authentication-Info header
*
* An Authentication-Info header has comma-separated list of parameters as its value.
*/
struct msg_auth_info_s
{
msg_common_t ai_common[1]; /**< Common fragment info */
msg_error_t *ai_next; /**< Dummy link to next */
msg_param_t const *ai_params; /**< List of ainfo */
};
/** Unknown header. */
struct msg_unknown_s {
msg_common_t un_common[1]; /**< Common fragment info */
msg_unknown_t *un_next; /**< Link to next unknown header */
char const *un_name; /**< Header name */
char const *un_value; /**< Header field value */
};
/** Erroneus header. */
struct msg_error_s {
msg_common_t er_common[1]; /**< Common fragment info */
msg_error_t *er_next; /**< Link to next header */
char const *er_name; /**< Name of bad header (if any). */
};
/** Separator. */
struct msg_separator_s {
msg_common_t sep_common[1]; /**< Common fragment info */
msg_error_t *sep_next; /**< Dummy link to next header */
char sep_data[4]; /**< NUL-terminated separator */
};
/** Message payload. */
struct msg_payload_s {
msg_common_t pl_common[1]; /**< Common fragment info */
msg_payload_t *pl_next; /**< Next payload chunk */
char *pl_data; /**< Data - may contain NUL */
usize_t pl_len; /**< Length of message payload */
};
/** Any header. */
union msg_header_u {
msg_common_t sh_common[1]; /**< Common fragment info */
struct {
msg_common_t shn_common;
msg_header_t *shn_next;
} sh_header_next[1];
#define sh_next sh_header_next->shn_next
#define sh_class sh_common->h_class
#define sh_succ sh_common->h_succ
#define sh_prev sh_common->h_prev
#define sh_data sh_common->h_data
#define sh_len sh_common->h_len
msg_generic_t sh_generic[1];
msg_numeric_t sh_numeric[1];
msg_list_t sh_list[1];
msg_auth_t sh_auth[1];
msg_separator_t sh_separator[1];
msg_payload_t sh_payload[1];
msg_unknown_t sh_unknown[1];
msg_error_t sh_error[1];
};
/* ====================================================================== */
/**Define how to handle existing headers
* when a new header is added to a message.
*/
typedef enum {
msg_kind_single, /**< Only one header is allowed */
msg_kind_append, /**< New header is appended */
msg_kind_list, /**< A token list header,
* new header is combined with old one. */
msg_kind_apndlist, /**< A complex list header. */
msg_kind_prepend /**< New header is prepended */
} msg_header_kind_t;
struct su_home_s;
typedef issize_t msg_parse_f(struct su_home_s *, msg_header_t *, char *, isize_t);
typedef issize_t msg_print_f(char buf[], isize_t bufsiz,
msg_header_t const *, int flags);
typedef char *msg_dup_f(msg_header_t *dst, msg_header_t const *src,
char *buf, isize_t bufsiz);
typedef isize_t msg_xtra_f(msg_header_t const *h, isize_t offset);
typedef int msg_update_f(msg_common_t *, char const *name, isize_t namelen,
char const *value);
/** Factory object for a header.
*
* The #msg_hclass_t object, "header class", defines how a header is
* handled. It has parsing and printing functions, functions used to copy
* header objects, header name and other information used when parsing,
* printing, removing, adding and replacing headers within a message.
*/
struct msg_hclass_s
{
/* XXX size of header class missing. Someone has saved bits in wrong place. */
int hc_hash; /**< Header name hash or ID */
msg_parse_f *hc_parse; /**< Parse header. */
msg_print_f *hc_print; /**< Print header. */
msg_xtra_f *hc_dxtra; /**< Calculate extra size for dup */
msg_dup_f *hc_dup_one; /**< Duplicate one header. */
msg_update_f *hc_update; /**< Update parameter(s) */
char const *hc_name; /**< Full name. */
short hc_len; /**< Length of hc_name. */
char hc_short[2];/**< Short name, if any. */
unsigned char hc_size; /**< Size of header structure. */
unsigned char hc_params; /**< Offset of parameter list */
unsigned hc_kind:3; /**< Kind of header (#msg_header_kind_t):
* single, append, list, apndlist, prepend. */
unsigned hc_critical:1; /**< True if header is critical */
unsigned /*pad*/:0;
};
#define HC_LEN_MAX SHRT_MAX
SOFIA_END_DECLS
#endif /* !defined MSG_TYPES_H */
@@ -0,0 +1,413 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup test_msg
* @file test_class.c
*
* Message class for testing parser and transports.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Tue Mar 5 11:57:20 2002 ppessi
*/
#include "config.h"
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#define TAG_NAMESPACE "tst"
#include <test_class.h>
#include <sofia-sip/msg_parser.h>
#include <sofia-sip/msg_mclass.h>
#include <test_protos.h>
#include <sofia-sip/msg_addr.h>
extern msg_mclass_t const msg_test_mclass[1];
extern msg_mclass_t const *msg_test_default(void)
{
return msg_test_mclass;
}
#define msg_generic_update NULL
/**@ingroup test_msg
* @defgroup msg_test_request Request Line for Testing
*/
static msg_xtra_f msg_request_dup_xtra;
static msg_dup_f msg_request_dup_one;
msg_hclass_t msg_request_class[] =
MSG_HEADER_CLASS(msg_, request, NULL, "", rq_common,
single_critical, msg_request, msg_generic);
/** Decode a request line */
issize_t msg_request_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
msg_request_t *rq = (msg_request_t *)h;
char *uri, *version;
if (msg_firstline_d(s, &uri, &version) < 0 || !uri ||
url_d(rq->rq_url, uri) < 0)
return -1;
rq->rq_method_name = s;
rq->rq_version = version;
return 0;
}
/**Encode a request line. */
issize_t msg_request_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
msg_request_t const *rq = (msg_request_t const *)h;
return snprintf(b, bsiz, "%s " URL_FORMAT_STRING " %s" CRLF,
rq->rq_method_name,
URL_PRINT_ARGS(rq->rq_url),
rq->rq_version);
}
isize_t msg_request_dup_xtra(msg_header_t const *h, isize_t offset)
{
isize_t rv = offset;
msg_request_t const *rq = (msg_request_t const *)h;
rv += url_xtra(rq->rq_url);
rv += MSG_STRING_SIZE(rq->rq_method_name);
rv += MSG_STRING_SIZE(rq->rq_version);
return rv;
}
/** Duplicate one request header. */
char *msg_request_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra)
{
msg_request_t *rq = (msg_request_t *)dst;
msg_request_t const *o = (msg_request_t const *)src;
char *end = b + xtra;
URL_DUP(b, end, rq->rq_url, o->rq_url);
MSG_STRING_DUP(b, rq->rq_method_name, o->rq_method_name);
MSG_STRING_DUP(b, rq->rq_version, o->rq_version);
assert(b <= end);
return b;
}
/**@ingroup test_msg
* @defgroup msg_test_status Status Line for Testing
*/
static msg_xtra_f msg_status_dup_xtra;
static msg_dup_f msg_status_dup_one;
msg_hclass_t msg_status_class[1] =
MSG_HEADER_CLASS(msg_, status, NULL, "", st_common,
single_critical, msg_status, msg_generic);
/** Parse status line */
issize_t msg_status_d(su_home_t *home, msg_header_t *h, char *s, isize_t slen)
{
msg_status_t *st = (msg_status_t *)h;
char *status, *phrase;
unsigned long code;
if (msg_firstline_d(s, &status, &phrase) < 0 ||
(code = strtoul(status, &status, 10)) >= 1000 || *status)
return -1;
st->st_status = code;
st->st_phrase = phrase;
st->st_version = s;
return 0;
}
issize_t msg_status_e(char b[], isize_t bsiz, msg_header_t const *h, int flags)
{
msg_status_t const *st = (msg_status_t const *)h;
int status = st->st_status;
if (status > 999 || status < 100)
status = 0;
return snprintf(b, bsiz, "%s %03u %s" CRLF,
st->st_version, status, st->st_phrase);
}
/** Extra size of a msg_status_t object. */
isize_t msg_status_dup_xtra(msg_header_t const *h, isize_t offset)
{
isize_t rv = offset;
msg_status_t const *st = (msg_status_t const *)h;
rv += MSG_STRING_SIZE(st->st_version);
rv += MSG_STRING_SIZE(st->st_phrase);
return rv;
}
/** Duplicate one status header. */
char *msg_status_dup_one(msg_header_t *dst, msg_header_t const *src,
char *b, isize_t xtra)
{
msg_status_t *st = (msg_status_t *)dst;
msg_status_t const *o = (msg_status_t const *)src;
char *end = b + xtra;
MSG_STRING_DUP(b, st->st_version, o->st_version);
st->st_status = o->st_status;
MSG_STRING_DUP(b, st->st_phrase, o->st_phrase);
assert(b <= end); (void)end;
return b;
}
/** Extract the message body, including separator line.
*
* @param[in,out] msg message object
* @param[in,out] pub public message structure
* @param[in] b buffer containing unparsed data
* @param[in] bsiz buffer size
* @param[in] eos true if buffer contains whole message
*
* @retval -1 error
* @retval 0 message is incomplete
* @retval other number of bytes extracted
*/
issize_t msg_test_extract_body(msg_t *msg, msg_pub_t *pub,
char b[], isize_t bsiz, int eos)
{
msg_test_t *tst = (msg_test_t *)pub;
ssize_t m = 0;
size_t body_len;
if (!(tst->msg_flags & MSG_FLG_BODY)) {
/* We are looking at a potential empty line */
m = msg_extract_separator(msg, (msg_pub_t *)tst, b, bsiz, eos);
if (m == 0 || m == -1)
return m;
tst->msg_flags |= MSG_FLG_BODY;
b += m;
bsiz -= m;
}
if (tst->msg_content_length)
body_len = tst->msg_content_length->l_length;
else if (MSG_IS_MAILBOX(tst->msg_flags)) /* message fragments */
body_len = 0;
else if (eos)
body_len = bsiz;
else
return -1;
if (body_len == 0) {
tst->msg_flags |= MSG_FLG_COMPLETE;
return m;
}
if (m)
return m;
if ((m = msg_extract_payload(msg, (msg_pub_t *)tst, NULL, body_len, b, bsiz, eos) ) == -1)
return -1;
tst->msg_flags |= MSG_FLG_FRAGS;
if (bsiz >= body_len)
tst->msg_flags |= MSG_FLG_COMPLETE;
return m;
}
msg_href_t const msg_content_length_href[1] =
{{
msg_content_length_class,
offsetof(msg_test_t, msg_content_length)
}};
#include <sofia-sip/su_tag_class.h>
#include <sofia-sip/su_tag_inline.h>
#include <sofia-sip/su_tagarg.h>
#include <sofia-sip/msg_tag_class.h>
tagi_t *tsttag_filter(tagi_t *dst,
tagi_t const f[],
tagi_t const *src,
void **bb);
/** Tag class for test header tags. @HIDE */
tag_class_t tsthdrtag_class[1] =
{{
sizeof(tsthdrtag_class),
/* tc_next */ NULL,
/* tc_len */ NULL,
/* tc_move */ NULL,
/* tc_xtra */ msghdrtag_xtra,
/* tc_dup */ msghdrtag_dup,
/* tc_free */ NULL,
/* tc_find */ NULL,
/* tc_snprintf */ msghdrtag_snprintf,
/* tc_filter */ tsttag_filter,
/* tc_ref_set */ t_ptr_ref_set,
/* tc_scan */ msghdrtag_scan,
}};
/** Tag class for TST header string tags. @HIDE */
tag_class_t tststrtag_class[1] =
{{
sizeof(tststrtag_class),
/* tc_next */ NULL,
/* tc_len */ NULL,
/* tc_move */ NULL,
/* tc_xtra */ t_str_xtra,
/* tc_dup */ t_str_dup,
/* tc_free */ NULL,
/* tc_find */ NULL,
/* tc_snprintf */ t_str_snprintf,
/* tc_filter */ NULL /* msgtag_str_filter */,
/* tc_ref_set */ t_ptr_ref_set,
/* tc_scan */ t_str_scan
}};
/** Tag class for TST message tags. @HIDE */
tag_class_t tstmsgtag_class[1] =
{{
sizeof(tstmsgtag_class),
/* tc_next */ NULL,
/* tc_len */ NULL,
/* tc_move */ NULL,
/* tc_xtra */ msgobjtag_xtra,
/* tc_dup */ msgobjtag_dup,
/* tc_free */ NULL,
/* tc_find */ NULL,
/* tc_snprintf */ msgobjtag_snprintf,
/* tc_filter */ NULL /* tsttag_tst_filter */,
/* tc_ref_set */ t_ptr_ref_set,
}};
tag_typedef_t tsttag_header =
{{ TAG_NAMESPACE, "header", tsthdrtag_class, 0 }};
tag_typedef_t tsttag_header_str = STRTAG_TYPEDEF(header_str);
/** Filter a TST header structure. */
tagi_t *tsttag_filter(tagi_t *dst,
tagi_t const f[],
tagi_t const *src,
void **bb)
{
tagi_t stub[2] = {{ NULL }};
tag_type_t sctt, tt = f->t_tag;
msg_hclass_t *hc = (msg_hclass_t *)tt->tt_magic;
assert(src);
sctt = src->t_tag;
if (sctt && sctt->tt_class == tstmsgtag_class) {
msg_test_t const *tst = (msg_test_t const *)src->t_value;
msg_mclass_t *mc = (msg_mclass_t *)tst->msg_ident;
msg_header_t const **hh = (msg_header_t const **)
msg_hclass_offset(mc, (msg_pub_t *)tst, hc);
msg_header_t const *h;
if (tst == NULL ||
(char *)hh >= ((char *)tst + tst->msg_size) ||
(char *)hh < (char const *)&tst->msg_request)
return dst;
h = *hh;
if (h == NULL)
return dst;
stub[0].t_tag = tt;
stub[0].t_value = (tag_value_t)h;
src = stub; sctt = tt;
}
if (tt != sctt)
return dst;
if (!src->t_value)
return dst;
else if (dst) {
return t_dup(dst, src, bb);
}
else {
*bb = (char *)*bb + t_xtra(src, (size_t)*bb);
return dst + 1;
}
}
/** Add duplicates of headers from taglist to the TST message. */
int tst_add_tl(msg_t *msg, msg_test_t *tst,
tag_type_t tag, tag_value_t value, ...)
{
tagi_t const *t;
ta_list ta;
ta_start(ta, tag, value);
for (t = ta_args(ta); t; t = tl_next(t)) {
if (!(tag = t->t_tag) || !(value = t->t_value))
continue;
if (TSTTAG_P(tag)) {
msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
msg_header_t *h = (msg_header_t *)value, **hh;
if (h == NULL)
;
else if (h == MSG_HEADER_NONE) { /* Remove header */
hh = msg_hclass_offset(msg_mclass(msg), (msg_pub_t *)tst, hc);
while (hh && *hh)
msg_header_remove(msg, (msg_pub_t *)tst, *hh);
} else if (msg_header_add_dup_as(msg, (msg_pub_t *)tst, hc, h) < 0)
break;
}
else if (TSTTAG_STR_P(tag)) {
msg_hclass_t *hc = (msg_hclass_t *)tag->tt_magic;
char const *s = (char const *)value;
if (s && msg_header_add_make(msg, (msg_pub_t *)tst, hc, s) < 0)
break;
}
else if (tag == tsttag_header_str) {
if (msg_header_add_str(msg, (msg_pub_t *)tst, (char const *)value) < 0)
break;
}
}
ta_end(ta);
return t ? -1 : 0;
}
@@ -0,0 +1,165 @@
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef TEST_CLASS_H
/** Defined when <test_class.h> has been included. */
#define TEST_CLASS_H
/**@ingroup test_msg
* @file test_class.h
* @brief Message and header classes for testing.
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Thu Jun 29 15:58:06 2000 ppessi
*/
#ifndef URL_H
#include <sofia-sip/url.h>
#endif
#ifndef MSG_H
#include <sofia-sip/msg.h>
#endif
#ifndef MSG_HEADER_H
#include <sofia-sip/msg_header.h>
#endif
#ifndef MSG_MIME_H
#include <sofia-sip/msg_mime.h>
#endif
#ifndef MSG_MCLASS_H
#include <sofia-sip/msg_mclass.h>
#endif
SOFIA_BEGIN_DECLS
#define MSG_TEST_PROTOCOL_TAG ((void *)(size_t)0xdeadbeef)
#define MSG_TEST_VERSION_CURRENT "msg/1.0"
extern msg_mclass_t const msg_test_mclass[1];
extern msg_href_t const msg_content_length_href[1];
typedef struct msg_request_s msg_request_t;
typedef struct msg_status_s msg_status_t;
/** Request line. */
struct msg_request_s {
msg_common_t rq_common[1]; /**< Common fragment info */
msg_header_t *rq_next; /**< Link to next header */
char const *rq_method_name; /**< Method name */
url_t rq_url[1]; /**< RequestURI */
char const *rq_version; /**< Protocol version */
};
/** Status line. */
struct msg_status_s {
msg_common_t st_common[1]; /**< Common fragment info */
msg_header_t *st_next; /**< Link to next (dummy) */
char const *st_version; /**< Protocol version */
int st_status; /**< Status code */
char const *st_phrase; /**< Status phrase */
};
/** Message object for tests. */
typedef struct msg_test_s {
msg_common_t msg_common[1]; /**< For recursive inclusion */
msg_pub_t *msg_next;
void *msg_user; /**< User data */
unsigned msg_size;
unsigned msg_flags;
msg_error_t *msg_error;
msg_request_t *msg_request;
msg_status_t *msg_status;
/* === Headers start here */
msg_content_type_t *msg_content_type; /**< Content-Type */
msg_content_disposition_t *msg_content_disposition;
/**< Content-Disposition */
msg_content_location_t *msg_content_location; /**< Content-Location */
msg_content_language_t *msg_content_language; /**< Content-Language */
msg_accept_t *msg_accept; /**< Accept */
msg_accept_charset_t *msg_accept_charset; /**< Accept-Charset */
msg_accept_encoding_t *msg_accept_encoding; /**< Accept-Encoding */
msg_accept_language_t *msg_accept_language; /**< Accept-Language */
msg_mime_version_t *msg_mime_version; /**< MIME-Version */
msg_content_md5_t *msg_content_md5; /**< Content-MD5 */
msg_content_encoding_t *msg_content_encoding;
/**< Content-Encoding */
msg_content_length_t *msg_content_length; /**< Content-Length */
/* === Headers end here */
msg_unknown_t *msg_unknown;
msg_separator_t *msg_separator;
msg_payload_t *msg_payload;
msg_multipart_t *msg_multipart;
} msg_test_t;
union msg_test_u
{
msg_common_t sh_common[1];
struct {
msg_common_t shn_common;
msg_header_t *shn_next;
} sh_header_next[1];
msg_request_t sh_request[1];
msg_status_t sh_status[1];
msg_accept_t sh_accept[1];
msg_accept_charset_t sh_accept_charset[1];
msg_accept_encoding_t sh_accept_encoding[1];
msg_accept_language_t sh_accept_language[1];
msg_content_disposition_t sh_content_disposition[1];
msg_content_encoding_t sh_content_encoding[1];
msg_content_id_t sh_content_id[1];
msg_content_md5_t sh_content_md5[1];
msg_content_language_t sh_content_language[1];
msg_content_length_t sh_content_length[1];
msg_content_location_t sh_content_location[1];
msg_content_type_t sh_content_type[1];
msg_mime_version_t sh_mime_version[1];
msg_generic_t sh_generic[1];
msg_numeric_t sh_numeric[1];
msg_list_t sh_list[1];
msg_auth_t sh_auth[1];
msg_separator_t sh_separator[1];
msg_payload_t sh_payload[1];
msg_unknown_t sh_unknown[1];
};
issize_t msg_test_extract_body(msg_t *, msg_pub_t *,
char b[], isize_t bsiz, int eos);
static inline
msg_test_t *msg_test_public(msg_t *msg)
{
return (msg_test_t *)msg_public(msg, MSG_TEST_PROTOCOL_TAG);
}
SOFIA_END_DECLS
#endif /* !defined(TEST_CLASS_H) */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,359 @@
/**-*- c -*-
* @ingroup msg
* @internal @file test_protos.h.in
*
* Template for "test_protos.h".
*/
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
#ifndef TEST_PROTOS_H
/** Defined when <test_protos.h> has been included. */
#define TEST_PROTOS_H
/**@ingroup test_msg
* @file test_protos.h
*
* Prototypes and macros for dummy testing protocol headers.
*
* #AUTO#
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*/
#include <sofia-sip/su_config.h>
#include <sofia-sip/su_tag.h>
#include <sofia-sip/su_tag_class.h>
#ifndef MSG_HEADER_H
#include <sofia-sip/msg_header.h>
#endif
#ifndef MSG_MIME_PROTOS_H
#include <sofia-sip/msg_mime_protos.h>
#endif
#ifndef TEST_CLASS_H
#include <test_class.h>
#endif
SOFIA_BEGIN_DECLS
/** Test if tag type marks a msg_test_t structure. @HIDE */
#define TSTTAG_P(tt) ((tt)->tt_class == tsthdrtag_class)
/** Test if tag type marks a TST header string. @HIDE */
#define TSTTAG_STR_P(tt) ((tt)->tt_class == tststrtag_class)
/** Test if tag type marks a TST header structure. @HIDE */
#define TSTTAG_TST_P(tt) ((tt)->tt_class == tstmsgtag_class)
/** Test if tag item contains msg_test_t structure. @HIDE */
#define TSTTAGI_P(t) (TSTTAG_P((t)->t_tag))
/** Test if tag item contains a TST header string. @HIDE */
#define TSTTAGI_STR_P(t) (TSTTAG_STR_P((t)->t_tag))
/** Test if tag item contains a TST header structure. @HIDE */
#define TSTTAGI_TST_P(t) (TSTTAG_TST_P((t)->t_tag))
/** Tag class for TST headers */
extern tag_class_t tsthdrtag_class[1];
/** Tag class for string values of TST headers */
extern tag_class_t tststrtag_class[1];
/** Tag class for TST message */
extern tag_class_t tstmsgtag_class[1];
/**Tag list item for header string.
*
* The TSTTAG_HEADER_STR() macro is used to include a tag item containing a
* header string in the tag list, e.g.,
* @code
* TSTTAG_HEADER_STR("Priority: urgent").
* @endcode
*
* @param x pointer to a string, or NULL.
*
* @HIDE
*/
#define TSTTAG_HEADER(x) tsttag_header, tsttag_header_v((x))
/** Tag for header string */
extern tag_typedef_t tsttag_header;
#define TSTTAG_HEADER_REF(x) tsttag_header_ref, tsttag_header_vr(&(x))
extern tag_typedef_t tsttag_header_ref;
#if HAVE_INLINE
static inline tag_value_t
tsttag_header_v(msg_header_t const *v)
{ return (tag_value_t)v; }
static inline tag_value_t
tsttag_header_vr(msg_header_t const **vp)
{ return (tag_value_t)vp; }
#else
#define tsttag_header_v(v) (tag_value_t)(v)
#define tsttag_header_vr(vp) (tag_value_t)(vp)
#endif
/**Tag list item for header string.
*
* The TSTTAG_HEADER_STR() macro is used to include a tag item containing a
* header string in the tag list.
*
* @param x pointer to a string, or NULL.
*
* @HIDE
*/
#define TSTTAG_HEADER_STR(x) tsttag_header_str, tag_str_v((x))
/** Tag for header string */
extern tag_typedef_t tsttag_header_str;
#define TSTTAG_HEADER_STR_REF(x) tsttag_header_str_ref, tag_str_vr(&(x))
extern tag_typedef_t tsttag_header_str_ref;
#if HAVE_INLINE
static inline
tag_value_t tsttag_tst_v(msg_test_t const *v) { return (tag_value_t)v; }
static inline
tag_value_t tsttag_tst_vr(msg_test_t const **vp) { return (tag_value_t)vp; }
#else
#define tsttag_tst_v(v) (tag_value_t)(v)
#define tsttag_tst_vr(vp) (tag_value_t)(vp)
#endif
/**@addtogroup test_msg_#xxxxxx#*//**@{*/
/** Parse a #xxxxxxx_xxxxxxx#. @internal */
msg_parse_f msg_#xxxxxx#_d;
/** Print a #xxxxxxx_xxxxxxx#. @internal */
msg_print_f msg_#xxxxxx#_e;
/**Header class for #xxxxxxx_xxxxxxx#.
*
* The header class msg_#xxxxxx#_class defines how a
* #xxxxxxx_xxxxxxx# is parsed and printed. It also
* contains methods used by message parser and other functions
* to manipulate the msg_#xxxxxx#_t header structure.
*/
extern msg_hclass_t msg_#xxxxxx#_class[];
/**Initializer for structure msg_#xxxxxx#_t.
*
* A static msg_#xxxxxx#_t structure must be initialized
* with the MSG_#XXXXXX#_INIT() macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx# = MSG_#XXXXXX#_INIT;
*
* @endcode
* @HI
*/
#define MSG_#XXXXXX#_INIT() MSG_HDR_INIT(#xxxxxx#)
/**Initialize a structure msg_#xxxxxx#_t.
*
* An msg_#xxxxxx#_t structure can be initialized with the
* msg_#xxxxxx#_init() function/macro. For instance,
* @code
*
* msg_#xxxxxx#_t msg_#xxxxxx#;
*
* msg_#xxxxxx#_init(&msg_#xxxxxx#);
*
* @endcode
* @HI
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_init(msg_#xxxxxx#_t x[1])
{
return MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t));
}
#else
#define msg_#xxxxxx#_init(x) \
MSG_HEADER_INIT(x, msg_#xxxxxx#_class, sizeof(msg_#xxxxxx#_t))
#endif
/**Test if header object is instance of msg_#xxxxxx#_t.
*
* The function msg_is_#xxxxxx#() returns true (nonzero) if
* the header class is an instance of #xxxxxxx_xxxxxxx#
* object and false (zero) otherwise.
*
* @param header pointer to the header structure to be tested
*
* @return
* The function msg_is_x#xxxxxx#() returns true (nonzero) if
* the header object is an instance of header #xxxxxx# and
* false (zero) otherwise.
*/
#if SU_HAVE_INLINE
su_inline int msg_is_#xxxxxx#(msg_header_t const *header)
{
return header && header->sh_class->hc_hash == msg_#xxxxxx#_hash;
}
#else
int msg_is_#xxxxxx#(msg_header_t const *header);
#endif
#define msg_#xxxxxx#_p(h) msg_is_#xxxxxx#((h))
/**Duplicate (deep copy) @c msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_dup() duplicates a header
* structure @a hdr. If the header structure @a hdr
* contains a reference (@c hdr->x_next) to a list of
* headers, all the headers in the list are duplicated, too.
*
* @param home memory home used to allocate new structure
* @param hdr header structure to be duplicated
*
* When duplicating, all parameter lists and non-constant
* strings attached to the header are copied, too. The
* function uses given memory @a home to allocate all the
* memory areas used to copy the header.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_dup(home, tst->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_dup() returns a pointer to the
* newly duplicated msg_#xxxxxx#_t header structure, or NULL
* upon an error.
*/
msg_#xxxxxx#_t *msg_#xxxxxx#_dup(su_home_t *home, msg_#xxxxxx#_t const *hdr);
/**Copy a msg_#xxxxxx#_t header structure.
*
* The function msg_#xxxxxx#_copy() copies a header structure @a
* hdr. If the header structure @a hdr contains a reference (@c
* hdr->h_next) to a list of headers, all the headers in that
* list are copied, too. The function uses given memory @a home
* to allocate all the memory areas used to copy the header
* structure @a hdr.
*
* @param home memory home used to allocate new structure
* @param hdr pointer to the header structure to be duplicated
*
* When copying, only the header structure and parameter lists
* attached to it are duplicated. The new header structure
* retains all the references to the strings within the old @a
* header, including the encoding of the old header, if present.
*
* @par Example
* @code
*
* #xxxxxx# = msg_#xxxxxx#_copy(home, tst->msg_#xxxxxx#);
*
* @endcode
*
* @return
* The function msg_#xxxxxx#_copy() returns a pointer to
* newly copied header structure, or NULL upon an error.
*/
msg_#xxxxxx#_t *msg_#xxxxxx#_copy(su_home_t *home,
msg_#xxxxxx#_t const *hdr);
/**Make a header structure msg_#xxxxxx#_t.
*
* The function msg_#xxxxxx#_make() makes a new
* msg_#xxxxxx#_t header structure. It allocates a new
* header structure, and decodes the string @a s as the
* value of the structure.
*
* @param home memory home used to allocate new header structure.
* @param s string to be decoded as value of the new header structure
*
* @note This function is usually implemented as a macro calling
* msg_header_make().
*
* @return
* The function msg_#xxxxxx#_make() returns a pointer to
* newly maked msg_#xxxxxx#_t header structure, or NULL upon
* an error.
*/
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s)
{
return (msg_#xxxxxx#_t *)msg_header_make(home, msg_#xxxxxx#_class, s);
}
#else
msg_#xxxxxx#_t *msg_#xxxxxx#_make(su_home_t *home, char const *s);
#endif
/**Make a #xxxxxxx_xxxxxxx# from formatting result.
*
* The function msg_#xxxxxx#_format() makes a new
* #xxxxxxx_xxxxxxx# object using formatting result as its
* value. The function first prints the arguments according to
* the format @a fmt specified. Then it allocates a new header
* structure, and uses the formatting result as the header
* value.
*
* @param home memory home used to allocate new header structure.
* @param fmt string used as a printf()-style format
* @param ... argument list for format
*
* @note This function is usually implemented as a macro calling
* msg_header_format().
*
* @return
* The function msg_#xxxxxx#_format() returns a pointer to newly
* makes header structure, or NULL upon an error.
*
* @HIDE
*/
#if SU_HAVE_INLINE
su_inline
#endif
msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
__attribute__((__format__ (printf, 2, 3)));
#if SU_HAVE_INLINE
su_inline msg_#xxxxxx#_t *msg_#xxxxxx#_format(su_home_t *home, char const *fmt, ...)
{
msg_header_t *h;
va_list ap;
va_start(ap, fmt);
h = msg_header_vformat(home, msg_#xxxxxx#_class, fmt, ap);
va_end(ap);
return (msg_#xxxxxx#_t *)h;
}
#endif
/** @} */
SOFIA_END_DECLS
#endif /* !defined(TEST_PROTOS_H) */
@@ -0,0 +1,57 @@
/**@ingroup test_msg
* @IFILE test_table.c.in
*
* Template for <test_table.c>.
*
* @date Created: Wed Feb 21 11:01:45 2001 ppessi
*/
/*
* This file is part of the Sofia-SIP package
*
* Copyright (C) 2005 Nokia Corporation.
*
* Contact: Pekka Pessi <pekka.pessi@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
*
*/
/**@ingroup test_msg
*
* @CFILE test_table.c
* @brief Parser table used for testing.
*
* #AUTO#
*
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
*
* @date Created: Wed Jan 22 19:03:21 EET 2003 ppessi
*/
#include "config.h"
#include <stddef.h>
#include <string.h>
#include <test_class.h>
#include <test_protos.h>
#include <sofia-sip/msg_mime_protos.h>
#include <sofia-sip/msg_mclass.h>